0
点赞
收藏
分享

微信扫一扫

RentrantReadWriteLock的锁降级



文章目录

  • 概要
  • RentrantReadWriteLock
  • 读锁和写锁
  • 技术细节:锁降级
  • 重点解析
  • 为何要在写锁中获取一个读锁,这样做的目的是什么?
  • 为何RentrantReadWriteLock不能做锁的升级?


概要

  • RentrantReadWriteLock如何做锁降级?
  • RentrantReadWriteLock可以做锁降级,为何无法做锁升级?

RentrantReadWriteLock

它是 ReadWriteLock 读写锁的默认实现,也能实现公平/非公平两种锁, 还能获取到读锁和写锁;

读锁和写锁

这两个名词很好理解,就是字面意思:

  • 读锁: 做的是读操作,例如: 读取数据库值,读取一个属性值,获取集合中的一个值等…,对这种操作加一把锁;
  • 写锁: 做的是写操作,例如: dml数据库,删除集合中的一个元素,更新集合中的元素等…,对这种操作加一把锁;

读写锁互斥原则

只要写锁获取成功,那么其他读写锁线程均阻塞;
当获取写锁的时候,如果该资源已被其他线程获取到读锁,那么写锁也会获取失败;(保证可见性)

  1. 读锁与读锁之间可以共享;
  2. 写锁与读锁/写锁均互斥;

技术细节:锁降级

锁降级指的是一个写锁,最终被降级成了读锁 伪代码如下:

public void processData() {
        readLock.lock();
        if (!update) {
            // 必须先释放读锁
            readLock.unlock();
            // 锁降级从写锁获取到开始
            writeLock.lock();
            try {
                if (!update) {
                    // 准备数据的流程(略)
                    update = true;
                }
                readLock.lock();
            } finally {
                writeLock.unlock();
            }
            // 锁降级完成,写锁降级为读锁
        }
        try {
            // 使用数据的流程(略)
        } finally {
            readLock.unlock();
        }
    }

这段代码中,锁降级由读锁开始,最终由读锁结束,但是中间,经历了很多;
读锁的最开始和最终结束,不是一个锁;
这里获取写锁也很好理解,因为我要完成对于update 的赋值,既修改,这是写操作;
在获取到写锁后,操作update ,在释放写锁之前,获取到一个读锁,然后再释放写锁;(这里是重点,为何??)
最终释放读锁,完成了锁的降级,从写锁,降级为读锁;

重点解析

在获取到写锁后,操作update ,在释放写锁之前,获取到一个读锁,然后再释放写锁;(这里是重点,为何??)

为何要在写锁中获取一个读锁,这样做的目的是什么?

1 当执行这段代码的时候,只有一个线程能够获取到写锁,其他线程会被阻塞在读锁和写锁的lock()方法上,如果不获取读锁,那么其他线程可能会立马获取到读锁,并修改update,会造成当前线程无法感知到变化,因为判断已经结束;

2 锁降级中读锁的获取是必要的,因为,当我获取到读锁之后,其他线程的写锁是无法获取成功的(保证可见性),其他读锁是可以获取成功的,所以这里读锁的获取,主要是为了防止其他写锁获取成功;最终完成了锁的降级

为何RentrantReadWriteLock不能做锁的升级?

目的也是保证数据可见性,如果读锁已被多个线程获取,其中任意线程成功获取了写锁并更新了数据,则其更新对其他获取到读锁的线程是不可见的。


举报

相关推荐

0 条评论