美文网首页
Java锁之读写锁

Java锁之读写锁

作者: bearPotMan | 来源:发表于2019-07-22 22:00 被阅读0次

在说读写锁之前先来了解一下什么是独占锁和共享锁。
独占锁

指该锁一次只能被一个线程所持有,对 ReentrantLock 和 synchronized 而言都是独占锁。

共享锁

指该锁可被多个线程锁所持有。

对 ReentrantReadWriteLock 而言,其读锁是共享锁,写锁是独占锁。
多个线程同时读一个资源类没有任何问题,所以为了满足并发量,读取共享资源应该是可以同时进行的。但是,如果有一个线程想去写共享资源,就不应该再有其他线程对该资源进行读或写。我们稍微做一下分析也就是如下结果:

读-读能共存
读-写不能共存
写-写不能共存

接下来我们实现一个简单的缓存功能,使用两种方式来实现。

  • 不使用读写锁
public class BeforeReadWriteLockDemo {
    public static void main(String[] args) {
        BeforeCache cache = new BeforeCache();
        // 写
        for(int i = 0; i < 5; i++){
            final int temp = i;
            new Thread(() -> {
                cache.set(temp + "", temp);
            }, "t1").start();
        }
        // 读
        for(int i = 0; i < 5; i++){
            final int temp = i;
            new Thread(() -> {
                cache.get(temp + "");
            }, "t2").start();
        }
    }
}

class BeforeCache {
    private volatile Map<String, Object> cache = new HashMap<>();

    public void set(String key, Object value) {
        System.out.println(Thread.currentThread().getName() + " 正在写入:" + key);
        cache.put(key, value);
        try {
            TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}
        System.out.println(Thread.currentThread().getName() + " 写入 " + key + " 完成");
    }

    public void get(String key) {
        System.out.println(Thread.currentThread().getName() + " 正在读取:" + key);
        Object result = cache.get(key);
        System.out.println(Thread.currentThread().getName() + " 读取 " + result + " 完成");
    }
}

我们来看一下输出结果:

t1 正在写入:0
t1 正在写入:1
t1 正在写入:2
t1 正在写入:3
t1 正在写入:4
t2 正在读取:0
t2 读取 0 完成
t2 正在读取:1
t2 正在读取:2
t2 读取 1 完成
t2 读取 2 完成
t2 正在读取:3
t2 读取 3 完成
t2 正在读取:4
t2 读取 4 完成
t1 写入 0 完成
t1 写入 1 完成
t1 写入 3 完成
t1 写入 4 完成
t1 写入 2 完成

通过观察上述输出结果,发现写操作中途会被插入其他的操作,我们的要求是线程在进行写的过程应该是单一的,也就是阻塞的,然而上述的操作好像并不是。其实使用之前我们说的 ReentrantLock 也是可以的,但是对于读的场景来说并不需要阻塞,我们只要求写操作是单一的即可,为了达到多线程环境下写操作独占锁和读操作共享锁,也就是出于性能考虑,我们使用 J.U.C 包中的读写锁 ReentrantReadWriteLock 来实现基于读写锁的缓存功能。看下述代码实现。

  • 使用读写锁
public class AfterReadWriteLockDemo {
    public static void main(String[] args) {
        AfterCache cache = new AfterCache();
        // 写
        for(int i = 0; i < 5; i++){
            final int temp = i;
            new Thread(() -> {
                cache.set(temp + "", temp);
            }, "t1").start();
        }
        // 读
        for(int i = 0; i < 5; i++){
            final int temp = i;
            new Thread(() -> {
                cache.get(temp + "");
            }, "t2").start();
        }
    }
}

class AfterCache {
    private volatile Map<String, Object> cache = new HashMap<>();
    private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    public void set(String key, Object value) {
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " 正在写入:" + key);
            cache.put(key, value);
            try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}
            System.out.println(Thread.currentThread().getName() + " 写入 " + key + " 完成");
        } catch (Exception e) {
          e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

    public void get(String key) {
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " 正在读取:" + key);
            Object result = cache.get(key);
            System.out.println(Thread.currentThread().getName() + " 读取 " + result + " 完成" );
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }
}

运行结果:

t1 正在写入:0
t1 写入 0 完成
t1 正在写入:2
t1 写入 2 完成
t1 正在写入:1
t1 写入 1 完成
t1 正在写入:3
t1 写入 3 完成
t1 正在写入:4
t1 写入 4 完成
t2 正在读取:0
t2 读取 0 完成
t2 正在读取:1
t2 正在读取:3
t2 正在读取:2
t2 读取 2 完成
t2 正在读取:4
t2 读取 3 完成
t2 读取 1 完成
t2 读取 4 完成

通过观察上述的结果,确实跟我们预想的是一致的,这也就达到了 写独占与读共享 的目的。

相关文章

  • java并发之ReentrantReadWriteLock

    java并发之ReentrantReadWriteLock 知识导读 读写锁内部维护了两个分离的锁,读锁和写锁,两...

  • Java锁之读写锁

    在说读写锁之前先来了解一下什么是独占锁和共享锁。独占锁 指该锁一次只能被一个线程所持有,对 ReentrantLo...

  • ReentrantReadWriteLock源码解析

    ReentrantReadWriteLock编码示例 上面的代码展示读写锁的使用,读写锁的介绍参考Java锁[ht...

  • 锁2

    5、读写锁 相比Java中的锁(Locks in Java)里Lock实现,读写锁更复杂一些。假设你的程序中涉及到...

  • Java中对锁的理解

    Java中锁的种类划分 公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/读写锁 乐观锁/悲观锁 分段锁 偏向锁...

  • Java锁的种类

    JAVA锁有哪些种类,以及区别(转) 公平锁/非公平锁可重入锁独享锁/共享锁互斥锁/读写锁乐观锁/悲观锁分段锁偏向...

  • 锁小结

    JAVA中锁的分类 公平锁/非公平锁可重入锁独享锁/共享锁互斥锁/读写锁乐观锁/悲观锁分段锁偏向锁/轻量级锁/重量...

  • JAVA锁的那些事

    在学习java的过程中会遇到各个各样锁的概念:公平锁/非公平锁、可重入锁、单独锁/共享锁、互斥锁/读写锁、乐观锁/...

  • 谈谈对锁的理解

    参考:通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现! 在并发...

  • 9. 锁的类型

    锁的类型 根据排他性可以划分锁的类型为: 排它锁(或互斥锁) 读写锁 根据Java虚拟机对锁的实现方式可以划分锁的...

网友评论

      本文标题:Java锁之读写锁

      本文链接:https://www.haomeiwen.com/subject/htvcaqtx.html