• java多线程:并发包中ReentrantReadWriteLock读写锁的原理


    一:读写锁解决的场景问题
    --->数据的读取频率远远大于写的频率的场景,就可以使用读写锁。
    二:读写锁的结构
    --->用state一个变量。将其转化成二进制,前16位为高位,标记读线程获取锁的次数。后16位为低位,标记写线程获取锁的次数。
    --->读写锁需要解决的冲突:读/写冲突,写/写冲突。读/读之间无冲突。
    --->当有写线程获取锁的时候。state的二进制表现,低位有数字,高位全是0。当有读线程获取锁的时候,state的二进制表现,低位全是0,高位有数字。
    --->如何获取读线获取锁的次数呢?将state>>16得到的结果。如何获取写线程获取锁的次数呢?state&0x0000FFFF做按位与运算得到的结果。


    三:读写锁的公平和非公平模式
    非公平模式(默认):连续竞争的非公平锁可能无限期地推迟一个或多个reader或writer线程,但吞吐量通常要高于公平锁。
    公平模式:线程利用一个近似到达顺序的策略来争夺进入。当释放当前保持的锁时,可以为等待时间最长的单个writer线程分配写入锁,如果有一组等待时间大于所有正在等待的writer线程的reader,将为该组分配读者锁。
    试图获得公平写入锁的非重入的线程将会阻塞,除非读取锁和写入锁都自由(这意味着没有等待线程)。
    四:重入

    --->此锁允许reader和writer按照 ReentrantLock 的样式重新获取读取锁或写入锁。在写入线程保持的所有写入锁都已经释放后,才允许重入reader使用读取锁。


    五:写线程小于读线程的数量的时候,当写线程想获取锁的时候,如何提高写线程获取锁的概率。通过后继节点是否是共享节点机制实现。
    --->当读写锁底层的同步管理器为公平锁时,则严格按照顺序进行获取锁,当然读线程可以同时获取锁 体现在:readerShouldBlock()
    --->当读写锁底层的同步管理器为非公平锁时,则当下一个节点为写线程的节点,则当前获取锁的读线程则阻塞。提高写线程获取锁的概率。体现在readerShouldBlock()
    --->写线程形成的Node为排它节点。读线程形成的Node为共享节点。区别在于Node内部的属性nextWaiter的属性引用,若引用为null则为排它节点。若引用为Node.SHARED则为共享节点。

    六:读写锁的一些特性
    writer可以获取读取锁,但reader不能获取写入锁。
    锁降级:重入还允许从写入锁降级为读取锁,实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。但是,从读取锁升级到写入锁是不可能的。
    锁获取的中断:读取锁和写入锁都支持锁获取期间的中断。

    锁降级中读锁的获取是否必要呢?

    --->答案是必须的。主要是为了保证数据的可见性,如果当前线程不获取读锁而直接释放写锁,假设此刻另一个线程(记作线程T)获取了写锁并修改了数据,那么当前线程无法感知线程T的数据更新。如果当前线程获取读锁,即遵循锁降级的步骤,则线程T将会被阻塞,直到当前线程使用数据并释放读锁之后,线程T才能获取写锁进行更新。


    Condition 支持:写入锁提供了一个 Condition 实现,对于写入锁来说,该实现的行为与 ReentrantLock.newCondition() 提供的 Condition 实现对 ReentrantLock 所做的行为相同。当然,此 Condition 只能用于写入锁。
    读取锁不支持 Condition,readLock().newCondition() 会抛出 UnsupportedOperationException。
    监测:此类支持一些确定是读取锁还是写入锁的方法。这些方法设计用于监视系统状态,而不是同步控制




    七:读锁,获取锁和释放锁的原理图



    八读锁的获取和释放

  • 相关阅读:
    性格决定命运
    操作系统课程设计之生产者消费者问题
    Linux 操作系统学习之线程
    OpenCV 显示一幅图片
    对图像每个像素点量化
    css选择器
    极简主义,对逻辑操作符||和&&深度运用的理解
    slice的用法与用量
    简单重置移动端默认样式
    移动端视口格式化备注
  • 原文地址:https://www.cnblogs.com/shangxiaofei/p/5807546.html
Copyright © 2020-2023  润新知