JUC中的读写锁(ReentrantReadWriteLock)

Posted XeonYu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC中的读写锁(ReentrantReadWriteLock)相关的知识,希望对你有一定的参考价值。

上一篇:
JUC中的线程通信 Condition

ReentrantReadWriteLock

在之前的文章中,我们已经介绍了ReadWriteLock 接口

JUC已经给我们提供了一个该接口的实现类,就是ReentrantReadWriteLock(可重入读写锁)

看一下读写锁普通锁的区别:

  • 读写锁维护了两把锁,分别是读锁写锁
  • 读写锁中的读锁可以同时被多个线程同时持有,写锁跟普通锁一样,同一时间只能被一个线程持有,读锁和写锁会相互排斥,属于悲观锁

下面我们来看个示例:

/*普通的可重入锁*/
class ReentranLockDemo {
    private final ReentrantLock reentrantLock = new ReentrantLock();


    private int num = 0;

    public void write() {

        reentrantLock.lock();

        try {

            TimeUnit.MILLISECONDS.sleep(500);
            num++;
            System.out.println("write num = " + num);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            reentrantLock.unlock();
        }


    }


    public void read() {

        reentrantLock.lock();

        try {
            TimeUnit.MILLISECONDS.sleep(500);
            System.out.println("\\"read\\"+num = " + num);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            System.out.println("reentrantLock.getHoldCount() = " + reentrantLock.getHoldCount());
            reentrantLock.unlock();
        }

    }

}


我们用了一个ReentrantLock 分别锁住read和write方法。

main方法代码如下:

    public static void main(String[] args) {
        ReentranLockDemo reentranLockDemo = new ReentranLockDemo();

        /*起10个线程执行read方法*/
        for (int i = 0; i < 10; i++) {
            new Thread(reentranLockDemo::read).start();
        }

        /*起10个线程执行write方法*/
        for (int i = 0; i < 10; i++) {
            new Thread(reentranLockDemo::write).start();
        }

    }

看下执行结果:

运行结果如上,符合预期。

下面我们将ReentrantLock换成ReentrantReadWriteLock 试一下:

/*读写锁*/
class ReadWriteLockDemo {

    private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();


    private int num = 0;

    public void write() {

        readWriteLock.writeLock().lock();

        try {

            TimeUnit.MILLISECONDS.sleep(500);
            num++;
            System.out.println("write num = " + num);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            readWriteLock.writeLock().unlock();
        }


    }


    public void read() {

        readWriteLock.readLock().lock();

        try {
            TimeUnit.MILLISECONDS.sleep(500);
            System.out.println("\\"read\\"+num = " + num);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("readWriteLock.getReadLockCount() = " + readWriteLock.getReadLockCount());
            readWriteLock.readLock().unlock();
        }

    }

}


main方法如下:

    public static void main(String[] args) {
        ReadWriteLockDemo readWriteLockDemo = new ReadWriteLockDemo();

        /*起10个线程执行read方法*/
        for (int i = 0; i < 10; i++) {
            new Thread(readWriteLockDemo::read).start();
        }

        /*起10个线程执行write方法*/
        for (int i = 0; i < 10; i++) {
            new Thread(readWriteLockDemo::write).start();
        }

    }

运行结果:

可以看到,读写锁在多线程读的情况下,ReentrantReadWriteLock执行速度明显比ReentrantLock快,而且可以看到ReentrantLock同一时间只会被一个线程持有,而ReentrantReadWriteLock中的读锁可以同时被多个线程持有

其中读锁和写锁是互斥的,也就是说假如线程持有了读锁,那么获取写锁的线程会被阻塞,同样的,假如写锁被其它线程持有,那么获取读锁的线程就会被阻塞。因此,ReentrantReadWriteLock是一种悲观锁

这就是读写锁为什么在读的时候会比普通锁执行效率的高的原因。

所以,读写锁非常适合用在 读多写少的同步操作中。


如果你觉得本文对你有帮助,麻烦动动手指顶一下,可以帮助到更多的开发者,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!

以上是关于JUC中的读写锁(ReentrantReadWriteLock)的主要内容,如果未能解决你的问题,请参考以下文章

JUC中的读写锁(ReentrantReadWriteLock)

JUC并发编程 共享模式之工具 JUC 读写锁 ReentrantReadWriteLock -- ReentrantReadWriteLock(不可重入锁)使用 & 注意事项

JUC包中的锁框架

JAVA JUC 读写锁

JUC之ReadWriteLockReentrantReadWriteLock读写锁

JUC之StampedLock读写锁增强辅助类