可重入锁机制和源码解析


一.概述:

锁分为可重入锁和不可重入锁,这两者的区别是什么?
可重入锁就是当一个线程获得了某个对象的实例并进入一个方法A,这个线程在没有释放锁的情况下能否再次进入方法A,就是可重入锁和不可重入锁的区别。

  • 可重入锁:能再次进入方法A,什么情况下需要再次进入方法A,对喽,就是递归调用这个加锁方法执行运算的时候,像synchronized和Reentrantlock都是可重入锁。
  • 不可重入锁:不能再次进入方法A,Mutex(互斥锁)是不可重入锁。

注:在看我这篇文章之前,建议先阅读以下几篇文章,对重入锁有一个大概的了解,顺序也按照我给出的顺序来阅读,我这篇文章只是对可重入锁的源码、CAS、AQS等进行一个总结,对于没有看过AQS或可重入锁的朋友来说不太容易懂。踏下心来看完我推荐的文章,基本对可重入锁(甚至互斥锁及其他锁)有一个比较深入的了解。

1.先学习一下可重入锁的使用方法
https://blog.csdn.net/u012545728/article/details/80843595
https://blog.csdn.net/soonfly/article/details/70918802

2.简单介绍可重入锁的原理,就像作者起的题目一样:轻松学习java可重入锁,这篇文章把可重入锁的机制解释的非常易懂生动。
https://blog.csdn.net/yanyan19880509/article/details/52345422

3.解释完了,直接看源码吧,这篇文章是我看过比较好的一篇介绍可重入锁源码的文章:
https://www.jianshu.com/p/7e1a1903d467

4.看完第三篇,是不是想了解下AQS:强烈推荐下面这篇讲解AQS的文章,妈呀,当我看完这篇文章之后,那叫一个通透,终于知道什么叫大牛,就是不单技术好,博客写的也NB
AQS:https://www.cnblogs.com/waterystone/p/4920797.html

5.读完AQS,是不是也想扫盲下CAS,那来吧:这篇把CAS连带Unsafe类将的比较通俗易懂
CAS:https://blog.csdn.net/mmoren/article/details/79185862

6.最后,记不记得第三篇文章提到了CAS自旋volatile变量,如果还感兴趣的朋友可以参考下这篇文章:
https://blog.csdn.net/holmofy/article/details/73824757

二.可重入锁机制及源码总结:

可重入锁分公平锁和非公平锁:线程老老实实在同步队列排队机制的锁叫公平锁,在之前线程释放锁期间可以加塞的锁叫非公平锁,可重入锁的默认锁是非公平锁。读完上面几篇文章后,可结合我的总结的源码图进行巩固(图片尺寸比较大,下载看更清楚,我传的是高清图),公平锁和非公平锁机制类似,因此这里只拿不公平锁举例。

可重入锁里面有三个内部类,Sync同步类,非公平锁类,公平锁类,其中Sync类给公平锁和非公平锁实现了一些共有方法,比如tryRelease()等方法,也给非公平锁实现了一些特定的比如nonfairTryAcquire()方法(还真是非公平啊...)。

可重入锁最基本最重要的方法就是lock()加锁和unLock()释放锁方法,这里重点介绍这两个方法。

可重入锁源码图.jpg

三.自定义同步器AQS:

谈到并发,不得不谈Reentrantlock,而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer,就像名字描述的,抽象队列同步器定义了一套多线程访问共享资源的同步器框架,许多类的实现都依赖它,比如
ReentrantLock、Semaphore、CountDownLatch等。

AQS维护了一个volatile state(代表共享资源)和FIFO线程等待队列(多线程竞争资源队列),不同自定义同步器竞争共享资源的方式不同,但自定义同步器在实现时只需实现共享资源state的获取与释放方式即可,至于线程等待队列的维护,AQS已经实现好了,主要有下面几个方法:

  • isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。
  • tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。
  • tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
  • tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
  • tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false。

AQS定义两种资源共享方式:独占模式(EXCLUSIVE,只有一个线程能执行,如Reentrantlock)和共享模式(Semaphore、CountDownLatch)。一般来说,自定义同步器要么是独占的,要么是共享的,也可兼有两种模式,比如ReentrantReadWritelock。我们实现某种模式只需要继承AQS,实现tryAcquire和tryRelease方法即可,这也是AQS不是接口而是类的原因,用什么模式只要实现那个模式对应的方法。

四.CAS:

CAS全称CompareAndSwap,核心算法是这样的:

CAS(V,E,N)//V-要更新的变量;E-旧值,或者叫期望值;N-要替换的新值;

在替换为新值之前,比较下变量V是否是当前的期望值,如果相等,替换,不相等,不做动作或重复检测。

锁分为悲观锁和乐观锁,在多线程环境下,

  • 悲观锁:如果在执行动作之前会认为可能发生锁冲突,在执行动作之前加锁的机制为悲观锁,对待操作是一种悲观的态度;
  • 乐观锁:在执行动作之前认为不会发生锁冲突,也不加锁,即无所操作,一旦发生所冲突再去解决冲突的机制为乐观锁,对待操作是一种乐观的态度;

而CAS就是一种乐观锁,他是一种系统级语言,因为系统原语的字节码指令执行时连续的,所以说CAS操作时一条CPU的原子指令操作,不会造成数据不一致的问题。

Unsafe类
我们接着深入一下,CAS在Java的实现环境中必须依赖鲜为人知的Unsafe类,可以理解为CAS操作是Unsafe类的一些方法。Unsafe这个类的方法都是被native()方法修饰的,意思是它的方法可以向操作C指针一样直接操作物理内存,直接调用操作系统底层资源执行相应任务。Unsafe类里CAS的相关操作涉及的方法如下:

//o为指定对象,offset为对象内存的偏移量,偏移量迅速定位字段并设置或获取该字段的值,
expected表示期望值,x表示要设置的值,下面3个方法都通过CAS原子指令执行操作。
public final native boolean compareAndSwapObject(Object o, long offset,Object expected, Object x);
public final native boolean compareAndSwapInt(Object o, long offset,int expected,int x);
public final native boolean compareAndSwapLong(Object o, long offset,long expected,long x);
  • 线程挂起与恢复
    在Java中,线程的挂起与恢复的相关操作被封装在LockSuport类中,但是其底层的还是通过Unsafe类的park()和unPark()方法实现的,
  • CAS使用场景
    从Java1.5开始,提供了java.util.concurrent.atomic包,在该包中有很多基于CAS操作实现的类,比如
AtomicBoolean:原子更新布尔类型
AtomicInteger:原子更新整型
AtomicLong:原子更新长整型

比如AtomicInteger的原子自增方法getAndAddInt()就是实现了CAS操作,从而保证了线程安全,有兴趣的朋友可以去看下源码。

后记:由于能力有限,若有错误或者不当之处,还请大家批评指正,一起学习交流!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容