java可重入锁ReentrantLock

6 篇文章 0 订阅
5 篇文章 0 订阅

一、使用

1、创建一个可重入锁 rL= ReentrantLock(true/false)
2、rL.lock()
3、try{业务代码块}
catch(){异常记录}
finally{ rL.unlock() 释放锁}

二、lock的时候发生了什么、线程处于怎样的状态

1、rL最重要的字段:抽象队列同步器 AbstractQueuedSynchronizer sync,负责获锁 acquire()。lock()里面就一行代码,就是让同步器sync去acquire()获锁。sync重要字段:state同步状态
2、acquire()获锁逻辑
1)首先尝试获锁tryAcquire()逻辑:
①如果同步状态为0,则通过CAS将其设为1,并且设置sync的占用线程为当前线程,并返回成功表明获锁成功。公平非公平的区别,在于公平锁,只有在当前线程节点是链表第一个时,才获得锁。
②否则,说明锁已被占用。两种情况,当前线程占,或者别的线程占。如果自己占,state值加1,并返回成功;如果别的占返回失败。
获锁成功直接返回了,lock()结束。
2)获锁失败
①先将当前线程作为一个节点,加入到等待线程节点双向链表的尾部,并返回当前线程节点
②从线程链表中获锁 acquireQueued(),自旋操作for(;;):如果当前线程节点为首节点,则调 用1)中的获锁tryAcquire()逻辑,成功则返回lock()结束;
③没有tryAcquire()成功,则判断,前面的线程节点都处于待唤醒状态(signal),如果是则执行part,park之后线程相当于执行了wait一样阻塞在这里,否则继续②中的自旋。
park的底层是调用了Unsafe类的park()函数,是一个native函数。
④线程获锁阻塞了以后,什么时候被唤醒——unlock登场

三、unlock释放锁的过程 及 唤醒其他的park的线程 sync的release()函数

可以执行unlock()说明当前线程占用了锁,释放锁的过程需要做两件事:给state设值和唤醒即unpark()链表中的首节点线程。流程为:同步状态变为state - 1,判断如果state变为0表示释放锁成功,并unpark()链表首节点对应的线程。unpark()相当于notify 也是Unsafe类native函数。

四、总结

1、出现了多次使用CAS(compare and swap)
1)在获锁将当前线程节点加入到链表尾部时,会出现多个线程同时操作的可能,使用CAS将当前线程节点加入到期望的尾结点的后面。底层是unsafe类
2)在设置同步状态时,也会出现多个线程同时操作的可能,也是用了CAS,如果期望的state为0时,才把state值设置为1。
2、核心要点在于 链表和同步器
3、较synchronized更丰富的功能的原因:
1)可中断:在进行自旋获锁的时候,会去检查是否线程标记了中断,获锁成功后会根据中断标记执行自中断操作(抛中断异常 终止线程)。避免出现死锁情况。
2)公平锁 :公平非公平的区别,在于公平锁,只有进行获锁tryAcquire()时,在当前线程节点是链表第一个时,才获得锁。
3)限时锁:在进行自选获锁的时候,加了时间判断,如果超时返回获锁失败。
4)可结合多个ConditionObject,实现高级特性的锁:如读写锁。 再如:LinkedBlockedQueue中两把锁takeLock和putLock,两个condition,notFull和notEmpty。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值