博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AbstractQueuedSynchronizer公平锁与非公平锁的实现
阅读量:2504 次
发布时间:2019-05-11

本文共 4467 字,大约阅读时间需要 14 分钟。

首先关于AbstractQueuedSynchronizer就不过多介绍了,在之前的文章中已经详细的介绍过了先关部分,不熟悉的同学建议先看之前的文章中的内容。

基本使用

ReentrantLock默认情况下是非公平锁,另外还提供了一个带boolean类型的构造方法,传入true,就表示要使用公平锁。

/**     * Creates an instance of {@code ReentrantLock}.     * This is equivalent to using {@code ReentrantLock(false)}.     */    public ReentrantLock() {
sync = new NonfairSync(); } /** * Creates an instance of {@code ReentrantLock} with the * given fairness policy. * * @param fair {@code true} if this lock should use a fair ordering policy */ public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync(); }

公平锁与非公平锁的实现区别

从源码上看,两者实现方式的区别十分简单,只有两处不一样。

1、调用lock方法时,如果是非公平锁的方式,首先会先通过CAS尝试获取一次锁,如果获取失败,才会调用acquire方法,而公平锁则是直接就调用acquire方法。

非公平锁

final void lock() {
if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }

公平锁

final void lock() {
acquire(1); }

2、tryAcquire方法,比较下两个方法,差别就是公平锁多了一个hasQueuedPredecessors方法。

非公平锁

protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires); } final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread(); int c = getState(); if (c == 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; }

公平锁

/**         * Fair version of tryAcquire.  Don't grant access unless         * recursive call or no waiters or is first.         */        protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) {
if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }

hasQueuedPredecessors这个方法想达到的目的就是判断当前等待队列是否已经有其他线程在等待了,如果有则返回true,如果没有则返回false。

public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); }

如果hasQueuedPredecessors返回了true,那么当前线程就不会继续尝试获取锁了,而是直接把自己添加到队列的尾部,通过addWaiter方法。

如果不去关注hasQueuedPredecessors方法的细节,直接带着结果来理解,实现公平与非公平的方式就很简单,公平锁的思想无非就是,每个线程在尝试获取锁前先判断等待队列中是否已经有别的线程了,如果有则加入到队列尾部,等待前一个线程唤醒,而非公平锁则不一样,lock方法时就会尝试获取一次锁,如果失败,则在tryAcquire时又会尝试获取一次锁,如果再失败才会去等待队列中排队。

流程图

在这里插入图片描述

再来分析hasQueuedPredecessors方法

public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); }

结合同步队列的图来理解

在这里插入图片描述

1、h != t

当这个条件为false时,则表示当前队列中为空,或者只有一个节点,所以为false时直接返回,当前线程可以尝试获取锁。

2、((s = h.next) == null || s.thread != Thread.currentThread())

(s = h.next) == null,首先当这个条件为true时,后面条件不需要判断,结合第一个条件来看,如果要满足h.next为null,看起来是很矛盾的事情,第一个条件中确认了此时队列中肯定不只一个节点,那么头节点为什么会不存在下一个节点呢?这个场景实际上是某一个节点正在处于入队过程中,next还没来及赋值,但是队列中肯定是已经存在别的线程了,所以直接返回true,让当前线程排队等待。

如果h.next不为null,那么就可以肯定当前队列中一定存在等待的线程,而s.thread != Thread.currentThread()就是为了判断,next线程与当前线程是否是同一个,如果是同一个则返回false,表示轮到自己了,那么当前线程就可以尝试获取锁了,如果不是同一个则返回true,当前线程去队列中排队。

转载地址:http://eolrb.baihongyu.com/

你可能感兴趣的文章
python爬虫 CSS选择器
查看>>
正常关闭java程序
查看>>
查看linux核心数
查看>>
数据结构与算法三: 数组
查看>>
Activiti工作流会签二 启动流程
查看>>
Activiti工作流会签三 撤销,审批,驳回
查看>>
Oauth2方式实现单点登录
查看>>
CountDownLatch源码解析加流程图详解--AQS类注释翻译
查看>>
ES相关度评分
查看>>
我们一起做一个可以商用的springboot脚手架
查看>>
idea在搭建ssm框架时mybatis整合问题 无法找到mapper
查看>>
java设计基本原则----单一职责原则
查看>>
HashMap的实现
查看>>
互斥锁 synchronized分析
查看>>
java等待-通知机制 synchronized和waity()的使用实践
查看>>
win10 Docke安装mysql8.0
查看>>
docker 启动已经停止的容器
查看>>
order by 排序原理及性能优化
查看>>
Lock重入锁
查看>>
docker安装 rabbitMq
查看>>