ReentrantLock之非公平锁源码分析
本文分析的ReentrantLock所对应的Java版本为JDK8。
在阅读本文前,读者应该知道什么是CAS、自旋。
由于ReentrantLock的公平锁和非公平锁中有许多共同代码,本文只会对这两种锁的不同之处加以分析,所以如果读者对公平锁不熟的话,强烈建议先看我的上篇博客——ReentrantLock之公平锁源码分析。
本文大纲
1.ReentrantLock非公平锁简介
2.lock方法
3.unlock方法
4.公平锁与非公平锁的异同
1. ReentrantLock非公平锁简介
ReentrantLock是JUC(java.util.concurrent)包中Lock接口的一个实现类,它是基于AbstractQueuedSynchronizer(下文简称AQS)来实现锁的功能。ReentrantLock的内部类Sync继承了AbstractQueuedSynchronizer,Sync又有FairSync和NonFairSync两个子类。FairSync实现了公平锁相关的操作,NonFairSync实现了非公平锁相关的操作。它们之间的关系如下:
非公平锁的不公平之处主要体现在,对于一个新来的线程,它会直接去抢占锁,不理会锁是否已经被占用或者该锁的等待队列中已经有其它的等待线程,如果抢占失败再进入等待队列队尾。
下面这段代码展示了非公平锁的使用方法:
private final Lock lock = new ReentrantLock(); // 调用ReentrantLock的空参构造方法,默认创建非公平锁 public void method() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock(); } }
2. lock方法
ReentrantLock的lock方法调用了NonFairSync的lock方法:
public void lock() { sync.lock(); }
NonFairSync的lock方法:
final void lock() { if (compareAndSetState(0, 1)) // 注意!!!在非公平锁中,会先用CAS的方式去尝试更改锁的状态,即尝试去获取锁,不管锁是否被其他线程持有,也不理会等待队列中是否有等待的线程 setExclusiveOwnerThread(Thread.currentThread()); // 获取锁成功,则将当前占有锁的线程设置为当前线程 else acquire(1); // CAS获取锁失败,则进入acquire方法 }
acquire方法:
public final void acquire(int arg) { if (!tryAcquire(arg) && // 这里将调用NonfairSync的tryAcquire方法 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 如果获取锁失败,执行acquireQueued方法,将把当前线程排入队尾 selfInterrupt(); }
tryAcquire方法:
protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }
nonfairTryAcquire方法:
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); // 获取锁的状态 if (c == 0) { // 如果状态是0,表示锁没有被占用 if (compareAndSetState(0, acquires)) { // 注意!!!在非公平锁中,这里不会判断队列中是否有等待的线程,非公平锁会直接去抢占锁 setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
请注意上文的代码注释中的有两个“注意!!!”,这两处就是公平锁和非公平锁的区别所在。
lock方法中,其它剩余的代码就和公平锁中的一样了,如果读者还需了解lock方法中后面的代码,请参见我的上篇博客。
3. unlock方法
和公平锁的unlock方法一样,请允许我偷个懒~ 还是参见我的上篇博客吧。
4. 公平锁与非公平锁的异同
- 在公平锁(FairSync)的lock方法中,会直接调用aquire方法;但是在非公平锁(NonfairSync)的lock方法中,会先采用CAS的方式去获取锁,不管是否有其他线程已经占有锁或者是否有其他线程在等待队列中。
- 公平锁(FairSync)调用的tryAcquire方法中,会先去检查等待队列中是否有等待的线程;但是在非公平锁(NonfairSync)调用的nonfairTryAcquire不会去检查等待队列。
- 无论公平锁还是非公平锁,对于排队中的线程,都能保证排在前面的线程一定比排在后面的线程优先获得锁。
- 哪种芯片架构将成为人工智能时代的开路先锋
- 算法系列(三)
- Facebook、Google、Amazon 是如何高效开会的
- 算法系列(二)
- JavaScript 基础(五) 函数 变量和作用域
- iOS8 、iPhone6 及iPhone6+:Apple touch icon 与Startup Image
- 算法系列
- .net页面生命周期
- JavaScript 基础(四) 循环
- 【译】WordPress 中的50个过滤器(6):第41-50个过滤器
- 【译】WordPress 中的50个过滤器(5):第31-40个过滤器
- 使用VS2010 C#开发ActiveX控件
- JavaScript 基础(三) 对象 条件判断
- “大数据+定制化服务”或将引领高端旅游市场
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【风险通告】XXL-JOB远程命令执行漏洞
- MySQL8.0特性之redo logging动态开关
- 3分钟短文:Laravel模型集合跟基类真不一样,别混为一谈
- 3分钟短文:Laravel模型一对一一对多关系真的乱吗?
- 3分钟短文:Laravel请求对象方法极多,可不是花拳绣腿
- 3分钟短文:Laravel验证用户输入,不要把啥都存到系统里
- 3分钟短文:Laravel用户自定义命令行简明教程
- 3分钟短文:Laravel命令行参数和可选项分不清?怎么可能!
- 《Offer一箩筐》求职之前你必须知道的 4 件事!!
- 3分钟短文:有趣的Laravel命令行交互,输入和输出!
- MySQL limit导致的执行计划差异
- 3分钟短文:用Laravel的方式管理服务器的文件们
- 漫画:什么是 “抽象工厂模式” ?
- 啥?Grafana 还能为日志添加告警?
- Docker映射详解,没问题了!