ReentrantLock的底层实现机制是AQS(Abstract Queued Synchronizer 抽象队列同步器)。AQS没有锁之类的概念,它有个state变量,是个int类型,为了好理解,可以把state当成锁,AQS围绕state提供两种基本操作“获取”和“释放”,有条双向队列存放阻塞的等待线程。AQS的功能可以分为独占和共享,ReentrantLock实现了独占功能(每次只能有一个线程能持有锁)。

在ReentrantLock类中,有一个内部类Sync,它继承了AQS,但是将lock()方法定义为抽象方法,由子类负责实现(采用的是模板方法的设计模式)。

abstract void lock();

Sync分为公平锁和非公平锁,所以又有FairSync和NonfairSync继承Sync。

ReentrantLock的默认构造实现是非公平锁,也就是线程获取锁的顺序和调用lock的顺序无关。所有线程同时去竞争锁,线程发出请求后立即尝试获取锁,如果有可用的则直接获取锁,失败才进入等待队列。

在非公平锁NonfairSync中,

线程只要有机会就抢占,才不管排队的事。直接尝试将state修改为1,如果修改state失败,则和公平锁一样,调用acquire。(乐观锁的思想)

在公平锁FairSync中,线程去竞争一个锁,可能成功也可能失败。成功就直接持有资源,不需要进入队列;失败的话进入队列阻塞,等待唤醒后再尝试竞争锁。

首先尝试着去获取锁,如果state的当前状态为0,且没有前继线程在等待,表明没有线程占用,此时可以获得锁,然后设置当前线程为独占线程,并返回true,此时不会调用acquireQueued()方法(&& : 只有当&&左边程序为真,才会执行&&右边的程序,否者不会执行后面的),且不会执行selfInterrupt()方法。

相反,如果获取锁失败,则会执行

acquireQueued(addWaiter(Node.EXCLUSIVE), arg)

该首先会将当前线程包装成一个Node,插入到双向队列尾

标记1判断该Node的前继节点p,如果前一个节点正好是head,表示自己排在第一位,可以马上调用tryAcquire尝试。如果获取成功就简单了,直接修改自己为head。这步是实现公平锁的核心。标记2是线程没有获取到锁的情况(当前线程没有排到第一位),这个时候,线程可能等着下一次获取,也可能不想要了,Node变量waitState描述了线程的等待状态。

shouldParkAfterFailedAcquire()方法会根据前一个节点的waitStatus作出抉择,如果前节点状态是SIGNAL,则当前线程需要阻塞。

如果线程需要阻塞,则由parkAndCheckInterrupt()方法进行操作。LockSupport和cas一样,最终使用UNSAFE调用Native方法实现线程阻塞(park和unpark方法作用类似于wait和notify)

释放锁:

public void unlock() {
sync.release(1);
}

头节点是获取锁的线程,如果tryRelease()释放成功,会将头节点先移出队列,再通知后面的节点获取锁

如果有后继节点,则唤醒线程,重新尝试去获取锁。

最新文章

  1. 关于owinstartupattribute的错误
  2. 服务器使用recast navigation
  3. eclipse如何安装cdt
  4. 一个特别不错的jQuery快捷键插件:js-hotkeys
  5. Android查询:模拟键盘鼠标事件(adb shell 实现)
  6. Android TextView文字描边的实现!!
  7. [MSSQL]最小公约数
  8. mongodb 高级操作
  9. WPF 10天修炼 第一天- 入门
  10. Confluence-6.10.0+Jira-7.13+Crowd-3.2.1最全破解文档,附下载包
  11. C#事务提交
  12. Linux编程 14 文件权限(用户列表passwd,用户控制shadow,useradd模板与useradd命令参数介绍)
  13. Windows环境selenium+Python环境配置
  14. Navicat11全系列激活工具和使用方法
  15. mysql数据库操作指令
  16. iOS开发-Block回调
  17. page 分页
  18. Eclipse build error 解决方法The library '*.jar' contains native libraries that will not run on the dev
  19. 个人常用的win7 快捷键
  20. Linux telnet命令详解

热门文章

  1. a &a &a[0]之间的区别和联系
  2. CS无线电语
  3. Ubuntu 16.04 安装 Phpmyadmin 出现的问题及解决
  4. Gartner提出的7种多租户模型
  5. llvm,gcc
  6. Storm-源码分析-Topology Submit-Worker
  7. Divisibility by Eight---cf550C(被8整除 暴力)
  8. docker网络实践
  9. robotium原理之获取WebElement元素
  10. java生成多位随机数方法