java readwritelock原理_java四种线程池

java readwritelock原理_java四种线程池前言前面介绍了java中排它锁,共享锁的底层实现机制,本篇再进一步,学习非常有用的读写锁。鉴于读写锁比其他的锁要复杂,不想堆一大波的文字,本篇会试图图解式说明,把读写锁的机制用另外一种方式阐述。

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

前言

前面介绍了java中排它锁,共享锁的底层实现机制,本篇再进一步,学习非常有用的读写锁。鉴于读写锁比其他的锁要复杂,不想堆一大波的文字,本篇会试图图解式说明,把读写锁的机制用另外一种方式阐述,鉴于本人水平有限,如果哪里有误,请不吝赐教。

公平读写锁

ReentrantReadWriteLock的锁策略有两种,分为公平策略和非公平策略,两者有些小区别,为便于理解,本小节将以示例的形式来说明多线程下,使用公平策略的读写锁是如何处理的。

首先看一下即将出场的伙伴们,我们一共会出场几个线程,还有用于实现读写机制的AQS同步器队列。每个线程中的 R(0)W(0)表示当前线程占用了多少读写锁。

这里写图片描述

接下来,我们一步步来看在公平策略下多线程并发的读写机制是怎样的。

1.线程A请求一个读锁,此时无人竞争锁,A获取读锁1,即线程A重入次数为1,如下所示:

这里写图片描述

2.线程B请求一个读锁,由于AQS中没有等待节点,当前处于读锁占有状态(线程A占有1个读锁),所以B成功获取读锁,如下所示:

这里写图片描述

3.这时候,线程C请求一个写锁,由于当前其他两个线程拥有读锁,写锁获取失败,线程C入队列,如下所示:

这里写图片描述

AQS初始化会创建一个空的头节点,C入队列,然后会休眠,等待其他线程释放锁唤醒。

4.线程D也来了,线程D想获取一个读锁,虽然当于处于读锁占有阶段,但是目前D不占有任何数量的读锁,而且同步器队列中已经有等待节点,这时候,由于公平策略,D不得已,一个字,等,如下图所示:

这里写图片描述

5.这时候,线程A执行完了,释放了读锁,由于B仍然占有读锁,所以释放后读锁仍然没有完全释放,写锁仍然没有机会执行,如下图所示:

这里写图片描述

6.这次,B也执行完了,执行完后,读锁全部释放,这时候会唤醒排在同步器队头的节点C,C成功获取一个写锁,如下图所示:

这里写图片描述

7.一旦任何一个线程获取了写锁,除了该线程自己,其它线程都将无法获取读锁和写锁,这时候,线程C再次请求一个读锁,这是允许的,但反过来如果一个线程先获取了读锁,再获取写法则是不行的。这时候的状态如下图所示:

这里写图片描述

8.这时候假设线程E也来了,E想获取读锁,由于当前处于写锁状态,直接入队,如下所示:

这里写图片描述

9.这会C终于把活干完了,把读锁和写锁都给释放了,然后线程D被唤醒,获取了读锁,如下图所示:

这里写图片描述

10.这时候,如果再来一个线程,比如A,也想获取读锁,由于节点中还有线程E在等待,而且当前线程A没有获取任何读锁,不是重入状态,所以只能置入队尾,如下图所示:

这里写图片描述

11.这时候,如果D再次调用了一次获取读锁,由于D属于可重入状态,所以直接把读锁+1即可,如下图所示:

这里写图片描述

12.由于D获取的是读锁,同步队列中的E等待的也是读锁,所以E会被唤醒,获取读锁继续执行,如下图所示:

这里写图片描述

13.同样的,由于线程A获取的是读锁,在E执行后,会唤醒线程A,A也可以获得读锁,并继续执行,如下图所示:

这里写图片描述

14.最后大家各自执行,悄然退场。

非公平读写锁

接下来我们再来看一下非公平策略读写锁机制又是如何的,为了更好的对比,我们沿用公平锁的流程。

由于获取读锁的逻辑比较复杂,我们在这里先简单进行归纳:

a. 如果当前全局处于无锁状态,则当前线程获取读锁

b. 如果当前全局处于读锁状态,且队列中没有等待线程,则当前线程获取读锁

c. 如果当前全局处于写锁占用状态(并且不是当前线程占有),则当前线程入队尾

d. 如果当前全局处于读锁状态,且等待队列中第一个等待线程想获取写锁,那么当前线程能够获取到读锁的条件为:当前线程获取了写锁,还未释放;当前线程获取了读锁,这一次只是重入读锁而已;其它情况当前线程入队尾。之所以这样处理一方面是为了效率,一方面是为了避免想获取写锁的线程饥饿,老是得不到执行的机会

e. 如果当前全局处于读锁状态,且等待队列中第一个等待线程不是写锁,则当前线程可以抢占读锁

获取写锁相对就比较简单了,规则如下:

h. 如果当前处于无锁状态,则当前线程获取写锁

i. 如果当前全局处于读锁状态,当前线程入队尾

j. 如果当前全局处于写锁状态,除非是重入获取写锁,否则入队尾

接下来我们看一遍流程:

1.线程A请求一个读锁,全局处于无锁状态,根据规则a,线程A获取了锁,如下图所示:

这里写图片描述

2.线程B请求一个读锁,根据规则b,线程B可以获取到读锁

这里写图片描述

3.这时候,线程C请求一个写锁,由于当前其他两个线程拥有读锁,写锁获取失败,线程C入队列(根据规则i),如下所示:

这里写图片描述

AQS初始化会创建一个空的头节点,C入队列,然后会休眠,等待其他线程释放锁唤醒。

4.线程D也来了,线程D想获取一个读锁,根据读锁规则d,队列中第一个等待线程C请求的是写锁,为避免写锁迟迟获取不到,并且线程D不是重入获取读锁,所以线程D也入队,如下图所示:

这里写图片描述

5.这时候,线程A执行完了,释放了读锁,由于B仍然占有读锁,所以释放后读锁仍然没有完全释放,写锁仍然没有机会执行,如下图所示:

这里写图片描述

6.这次,B也执行完了,执行完后,读锁全部释放,这时候会唤醒排在同步器队头的节点C,C成功获取一个写锁,如下图所示:

这里写图片描述

7.一旦任何一个线程获取了写锁,除了该线程自己,其它线程都将无法获取读锁和写锁,这时候,线程C再次请求一个读锁,这是允许的,但反过来如果一个线程先获取了读锁,再获取写锁则是不行的。这时候的状态如下图所示:

这里写图片描述

8.这时候假设线程E也来了,E想获取读锁,由于当前处于写锁状态,直接入队,如下所示:

这里写图片描述

9.这会C终于把活干完了,把读锁和写锁都给释放了,然后线程D被唤醒,获取了读锁,如下图所示:

这里写图片描述

10.这时候,如果再来一个线程,比如A,也想获取读锁,虽然等待队列中,E线程刚好还没被唤醒,但A线程是可以抢占读锁的(这里假设抢占到了),这个跟公平锁有明显的区别,如下图所示:

这里写图片描述

11.这时候,如果D再次调用了一次获取读锁,由于D属于可重入状态,所以直接把读锁+1即可,如下图所示:

这里写图片描述

12.由于当前状态下处于读锁状态,前面的线程D其实醒来后,是会同时唤醒线程E的,所以线程E也醒过来继续干活了,如下图所示:

这里写图片描述

13.同步队列中没有等待线程了,各个线程执行完后,一切相安无事了。

总结

考虑到业务的多样化,java5中提供的并发包中的工具类大部分都同时提供了公平及非公平策略,这两种策略下,一般而言,非公平锁吞吐会比较大,所以默认情况下都是使用的非公平策略。

本篇试图以尽量简单的方式来阐明读写锁的实现机制,为了直观,我们只考虑简单抽象的方式,实际在实现的时候,会使用CAS去竞争锁。特别是在非公平策略中的第10个步骤,这种情况下有可能E先获取了读锁。很多时候,我们在大致了解了实现步骤,流程之后,再去品味源码,就会更加的轻松。

最后还是建议大家在了解了思路之后,自己多看看源码,多思考,学到的才是属于自己的东西。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/169983.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • AI图像处理算法岗位整理[通俗易懂]

    AI图像处理算法岗位整理[通俗易懂]职位详情工作职责:负责开发Webex音视频媒体引擎,在windows,mac,ios,android,linux等平台上开发多媒体编解码,图像处理等算法。负责算法的逻辑,性能调优,汇编优化,或者GPU算法实现。对算法的设计,实现,调试,优化,测试以及metrics统计负责。职位要求:精通C/C++,在至少某一个开发平台上有5年以上产品开发经验对性能优化有丰富经验,理解如何设计高性能算法或者调试性能问题精通多线程编程,能利用多线程优化算法。熟悉arm或者x86汇编指令,intrinsic指

    2022年5月16日
    45
  • Pycharm踩坑(一) FileNotFoundError: [Errno 2] No such file or directory: ‘../data/users.txt‘ 目录结构「建议收藏」

    Pycharm踩坑(一) FileNotFoundError: [Errno 2] No such file or directory: ‘../data/users.txt‘ 目录结构「建议收藏」Python使用Pycharm运行程序提示:FileNotFoundError:[Errno2]Nosuchfileordirectory:’../data/users.txt’目录结构test/├──data└──testcases└──test.py在test.py中运行代码:withopen(‘../data/users.txt’)asf…

    2022年6月24日
    76
  • JAVA的HelloWorld代码编写

    JAVA的HelloWorld代码编写第一步:新建一个文本文档第二步:打开代码输入代码(注意大小写,Java对大小写很敏感)第三步:更改后缀为.java(这样这个文档就会成为一个原文件)第四步:按住shift键,鼠标右键单击,点击“在此处打开Powershell”第五步:在Powershell窗口里输入JavacHelloworld.java,会出现一个class文档第六步:在Powershell窗口里输入JavacHelloworld会输出HelloWorld…

    2022年5月8日
    454
  • PostgreSQL 9.6.1,9.5.5,9.4.10,9.3.15,9.2.19和9.1.24发布!

    PostgreSQL 9.6.1,9.5.5,9.4.10,9.3.15,9.2.19和9.1.24发布!

    2022年2月22日
    59
  • Android动画之ScaleAnimation使用[通俗易懂]

    Android动画之ScaleAnimation使用[通俗易懂]什么是ScaleAnimationScaleAnimation即缩放动画,应用场景特别多,比如常见的隐藏菜单点击显示下面我分两种方式来介绍ScaleAnimation如何使用。1.xml文件形式文件名:anim_scale_in.xml效果:呈现view放大显示效果源码:

    2022年10月15日
    3
  • 如何将word转为html_word转html工具

    如何将word转为html_word转html工具推荐可以试用FreeSpire.DocforJava免费控件哦,它支持将htmlstring和htmlfile转word,代码操作简单,转换效果也很好。Htmlfile转wordimportcom.spire.doc.*;importcom.spire.doc.documents.XHTMLValidationType;publicclasshtmlFileToWord{pu…

    2022年10月12日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号