首页 > 编程知识 正文

java读写锁实现原理,java可重入锁

时间:2023-05-03 17:32:44 阅读:39398 作者:3958

我读了几篇关于这个问题的文章,大部分不清楚,现在总结一下。

ReentrantReadWriteLock读写锁

ReentrantReadWriteLock读/写锁定可同时授予多个读线程的访问权限,并在访问写入线程时阻止所有读/写线程。 该锁定保持读取锁定和写入锁定,通过分离读取/写入锁定,与排他锁定相比,同时性大幅提高,适用于许多读取/写入较少的场景。

读写锁依靠AQS实现同步功能,读写状态为同步状态。 读/写锁定的自定义同步器必须保持同步状态,即一个int变量保持多个读线程和一个写线程的状态。 读写锁定将变量分割为两个部分,前16位读取,后16位表示写入。

为什么不使用两个int型变量分别表示读锁定和写锁定的状态,而是将一个int型变量state分割成一半呢? 这是无法用一次CAS 同时操作两个int变量,因此int型的前16位和后16位分别表示读锁定和写锁定的状态。

写锁定为可重入排他锁,如果当前线程已经获取写锁定,则增加写状态;如果当前线程获取写锁定,则获取读锁定,或者已经锁定写锁定写入锁定的释放与ReentrantLock的释放类似,每次释放时写入状态都会减少,写入状态为0时表示写入锁定已释放。

读锁定为可重入共享锁,可以同时从多个线程获取。 如果没有其他写入线程访问,则始终成功获取读锁定。 如果当前线程已经获得读锁定,请提高读状态。 如果在当前线程获取读锁定的同时写锁定已经由其他线程获取,则进入等待状态。 每次释放读取锁定时读取状态减少,减少值为(116 ),读取锁定的释放是线程安全的。

锁降级

所谓封锁,就是写锁定下降到读锁定。 如果当前线程有写锁定,并释放它,最后获取读锁定,则这种分阶段的过程不能称为封锁。 封锁是抓住(当前拥有的)写锁定,获取读锁定,然后释放(以前拥有的)写锁定的过程。

部分分析源代码(ReadLock读锁定对象) :

锁定方法

公共语音锁定((sync.acquire shared ) ) 1; } acquire共享方法

调用publicfinalvoidacquireshared (intarg ) ReentrantReadWriteLock的sync的tryAcquireShared方法if(tryacquireshared )0) }

thread current=thread.current thread (; //当前状态int c=getState (; //如果存在写入锁定,且写入锁定不等于当前线程,则返回。 否则,继续获取簧片锁。 if (排除计数(c )!=0 getExclusiveOwnerThread ()!=当前(返回- 1; //读锁定获取从上面可以看出,线程尝试执行读操作时,在获取读锁定时lock-acquire shared-tryacquireshared被嵌套调用,最终逻辑是写锁定是否被占用

锁降级的必要性

译文:需要获取封锁中的读锁定吗? 需要答案。 主要为了保证数据的可见性,假设当前线程在未获取读锁定的情况下直接释放写锁定,则当前另一线程(标记为线程t )获取写锁定并修改了数据,当前线程无法感知线程T的数据更新当前无线程也就是说,如果按照封锁中的步骤进行操作,线程t将被阻止,在当前线程使用数据释放读锁定之前,线程t无法获取写锁定并更新数据。

解读:

首先,必须正确理解“当前线程无法感知线程t中数据的更新”这句话。 这句话的意思并不是说会破坏数据的内存可视性。 当线程t获得写锁定后释放时,其他线程中的数据将更新。 也就是说,数据更新操作对于其他线程是可见的。 我个人认为原文作者想表达的意图是,修改其他线程的写入操作对当前线程来说可能只是“透明”。 换言之,当前线程原本只是想读到写锁释放时刻数据的值,但最后读到的数据实际上已经被其他线程篡改过

在另一个级别,如果没有封锁,则当前线程在解除写入锁定后被其他线程获取时,所有后续读取线程都将被阻止,并且在当前写入线程解除锁定之前不会唤醒。 因此,在这种情况下,大量线程将阻止唤醒开销。 使用封锁,当前线程可以在写入过程中将读取请求直接切换到读取状态。适用于边读边写的程序

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。