ReentrantLock 非公平锁不公平在哪
重入锁关键地带:
1:使用unsafe的cas方式对AQS中的state成员变量进行“原子加一”操作。
2:如果当前线程多次lock,相当于对state在原有值基础上继续加一操作;释放锁的条件为“原子减一”到0为止。
3:ReentrantLock在非公平锁问题:
严格上讲并不是完全的非公平,当线程未获取到锁,进入线程Node链表时,并且链表有多个节点的情况下仍然要排队park,等待链表的先驱节点去unPark后才能继续执行。
而非公平是在首次尝试加锁的时候没有去理会线程的等待链表,如果首次尝试失败以后,会尝试判断锁是否被释放,如果当前锁已经被释放,二次尝试加锁的时候仍然不理会其它线程的等待链表,会直接尝试枷锁。
4:公平锁的关注点在hasQueuedPredecessors方法中:
(1)如果链表未创建,尝试直接对资源加锁;
(2)如果链表的头节点的next节点为null,也直接尝试加锁(实际就是当前线程重入);
(3)如果当前线程和持有锁的线程是同一线程,也直接加锁(实际就是当前线程重入);
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());
}
ps:链表设计的比较巧妙,头节点要么是持有锁的节点,要么是Tread数据域是null的节点。因为在当前资源首次加锁的情况下是不进入链表等待的,作者虚拟出一个“替代节点”,一旦首次加锁执行完毕,那么会移除这个“替代节点”,让真正持有锁的节点成为链表的头节点。
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());
}
5:入链表以后等待加锁的过程:
当一个节点入队以后,方法会返回该节点对象;
(1)如果发现当前节点的前一个节点是头节点,则当前线程立马尝试一次加锁,不用等待头节点主动unPark,当然头节点也会进行unPark;如果这次加锁失败则判断前一个节点是否Signal状态,如果是该状态则当前线程会自己park中断掉,等待先驱节点的唤醒。如果先驱节点不是Signal而是CANCELLED,一直沿着链表向前找,直到找到Signal后将自己链接到该节点的后面。
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
(2)如果前驱结点不是head节点,那么直接执行是否中断逻辑。
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
汇总:
可以看出ReentrantLock的加锁机制相比1.6以前的sync关键字是轻量的:
(1)当只有1个线程加锁时,没有其它线程资源占用的情况,它并不会初始化等待链表,只有非常轻量的CAS操作。
(2)而且ReentrantLock支持对同一个资源多次加锁。
(3)即使存在队列,那么队列中第一个等待线程节点对象,会主动尝试去加锁。
ReentrantLock 非公平锁不公平在哪的更多相关文章
- 第五章 ReentrantLock源码解析1--获得非公平锁与公平锁lock()
最常用的方式: int a = 12; //注意:通常情况下,这个会设置成一个类变量,比如说Segement中的段锁与copyOnWriteArrayList中的全局锁 final Reentrant ...
- 【试验局】ReentrantLock中非公平锁与公平锁的性能测试
硬件环境: CPU:AMD Phenom(tm) II X4 955 Processor Memory:8G SSD(128G):/ HDD(1T):/home/ 软件环境: OS:Ubuntu14. ...
- lock 默认公平锁还是非公平锁?公平锁是如何定义?如何实现
ReentrantLock的实现是基于其内部类FairSync(公平锁)和NonFairSync(非公平锁)实现的. 其可重入性是基于Thread.currentThread()实现的: 如果当前线程 ...
- Java ReentrantLock中tryLock与lock的区别(非公平锁与公平锁)
设置同步状态,利用CAS操作. // CAS操作:如果当前状态值等于期望值,则自动将同步状态设置为给定的更新值 protected final boolean compareAndSetState(i ...
- java多线程20 : ReentrantLock中的方法 ,公平锁和非公平锁
公平锁与非公平锁 ReentrantLock有一个很大的特点,就是可以指定锁是公平锁还是非公平锁,公平锁表示线程获取锁的顺序是按照线程排队的顺序来分配的,而非公平锁就是一种获取锁的抢占机制,是随机获得 ...
- 理解ReentrantLock的公平锁和非公平锁
学习AQS的时候,了解到AQS依赖于内部的FIFO同步队列来完成同步状态的管理,当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成一个Node对象并将其加入到同步队列,同时会阻塞当 ...
- ReentrantLock中的公平锁与非公平锁
简介 ReentrantLock是一种可重入锁,可以等同于synchronized的使用,但是比synchronized更加的强大.灵活. 一个可重入的排他锁,它具有与使用 synchronized ...
- 深入了解ReentrantLock中的公平锁和非公平锁的加锁机制
ReentrantLock和synchronized一样都是实现线程同步,但是像比synchronized它更加灵活.强大.增加了轮询.超时.中断等高级功能,可以更加精细化的控制线程同步,它是基于AQ ...
- Java多线程系列--“JUC锁”05之 非公平锁
概要 前面两章分析了"公平锁的获取和释放机制",这一章开始对“非公平锁”的获取锁/释放锁的过程进行分析.内容包括:参考代码获取非公平锁(基于JDK1.7.0_40)释放非公平锁(基 ...
随机推荐
- LOJ P10011 愤怒的牛 题解
每日一题 day36 打卡 Analysis 非常水的二分模板,就直接二分答案,用贪心策略check就好了 #include<iostream> #include<cstdio> ...
- 洛谷 P1250 种树 题解
差分约束系统,维护前缀和,根据式子d[ b ] < = d[ e + 1 ] - t,可以看出要连e和b - 1,但占用了超级源点0,所以要把区间向后移,这样就可以用超级源点0来保持图的连通性( ...
- 过拟合产生的原因(Root of Overfitting)
之前在<过拟合和欠拟合(Over fitting & Under fitting)>一文中简要地介绍了过拟合现象,现在来详细地分析一下过拟合产生的原因以及相应的解决办法. 过拟合产 ...
- mysql in和not in
mysql> select * from table1; +----------+------------+-----+---------------------+-------+ | name ...
- 「APIO2018」选圆圈
传送门 Description 有\(n\)个圆,每次找到这些圆中半径最大中的编号最小的圆,删除ta及与其有交集的所有圆. 对于每个圆,求出它是被哪一个圆删除的. Solution K-D Tree ...
- EasyEarth三维可视化解决方案——智慧河长
EasyEarth—— 为河长装上“千里眼.顺风耳” 为各级河长办应急指挥.任务指派. 实绩考核提供快速直观的 高效.精准.智能化决策平台. 河长制背景 我国治水工作呈现出新老问题交织态势,河湖管理保 ...
- Portainer实战
Portainer是一个轻量级的Docker环境管理UI,可以管理docker host和docker swarm(我主要看中了能管理swarm这个,毕竟市面上能管理swarm的平台不多).之所以说是 ...
- java 73题以及答案
作者:乌枭原文:https://blog.csdn.net/qq_34039315/article/details/78549311 1.在java中守护线程和本地线程区别? java中的线程分为两种 ...
- 解决idea创建Maven项目速度慢
idea在创建maven项目的时候会去网上自动下载需要的插件,这样就会导致项目创建后一直处于下载插件的状态中,影响开发效率 此时我们可以在创建maven骨架的时候,加入键值对来让maven调用本地的骨 ...
- flowable表简要说明
1. Flowable数据库表命名规则 ACT_RE_* ’RE’表示repository(存储).RepositoryService接口操作的表.带此前缀的表包含的是静态信息,如,流程定义,流程的资 ...