ReentrantLock 实现
ReentrantLock 实现:
我们主要看一下非公平锁的实现:
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
//cas 原子性操作,将state 状态改变为1
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());//返回true ,说明目前现在还没有线程进来,那么就将当前的线程标记为锁的线程
else
//否则的话,执行如下逻辑
acquire(1);
}
执行如下方法(包含了主要的3个方法): tryAcquire addWaiter acquireQueued
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
//非公平锁实现
return nonfairTryAcquire(acquires);
}
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//获取当前state 的值这个值表示当前锁被重入的次数
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");
//标记state ,重入的次数
setState(nextc);
return true;
}
//表示线程未申请到锁
return false;
}
在线程未申请到锁的时候:会执行 addWaiter acquireQueued 这两个方法:
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
//预先处理下,解决性能问题
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
我们主要看一下如何将线程安全同步的加入到队列中: 如下典型的乐观锁的实现:cas +for 循环重试机制
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
完成了加入队列的操作后接下来就是 acquireQueued 操作了
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
//循环阻塞
for (;;) {
final Node p = node.predecessor();
//如果当前node 节点的上一个节点是head 以及state 状态=0 时候(有线程释放锁的时候)
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
//唯一出口
return interrupted;
}
//线程park 阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
ReentrantLock 实现的更多相关文章
- Java并发基础框架AbstractQueuedSynchronizer初探(ReentrantLock的实现分析)
AbstractQueuedSynchronizer是实现Java并发类库的一个基础框架,Java中的各种锁(RenentrantLock, ReentrantReadWriteLock)以及同步工具 ...
- 架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock
ReentrantLock 有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级. this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决 ...
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之三unlock方法分析
前篇博客LZ已经分析了ReentrantLock的lock()实现过程,我们了解到lock实现机制有公平锁和非公平锁,两者的主要区别在于公平锁要按照CLH队列等待获取锁,而非公平锁无视CLH队列直接获 ...
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之二lock方法分析
前一篇博客简单介绍了ReentrantLock的定义和与synchronized的区别,下面跟随LZ的笔记来扒扒ReentrantLock的lock方法.我们知道ReentrantLock有公平锁.非 ...
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之一简介
注:由于要介绍ReentrantLock的东西太多了,免得各位客官看累,所以分三篇博客来阐述.本篇博客介绍ReentrantLock基本内容,后两篇博客从源码级别分别阐述ReentrantLock的l ...
- java线程 公平锁 ReentrantLock(boolean fair)
一.公平锁 1.为什么有公平锁 CPU在调度线程的时候是在等待队列里随机挑选一个线程,由于这种随机性所以是无法保证线程先到先得的(synchronized控制的锁就是这种非公平锁).但这样就会产生饥饿 ...
- Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock
本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...
- 【JUC】JDK1.8源码分析之ReentrantLock(三)
一.前言 在分析了AbstractQueuedSynchronier源码后,接着分析ReentrantLock源码,其实在AbstractQueuedSynchronizer的分析中,已经提到过Ree ...
- Lock、ReentrantLock、synchronized、ReentrantReadWriteLock使用
先来看一段代码,实现如下打印效果: 1 2 A 3 4 B 5 6 C 7 8 D 9 10 E 11 12 F 13 14 G 15 16 H 17 18 I 19 20 J 21 22 K 23 ...
- java分析源码-ReentrantLock
一.前言 在分析了 AbstractQueuedSynchronier 源码后,接着分析ReentrantLock源码,其实在 AbstractQueuedSynchronizer 的分析中,已经提到 ...
随机推荐
- Centos7下GlusterFS分布式存储集群环境部署记录
0)环境准备 GlusterFS至少需要两台服务器搭建,服务器配置最好相同,每个服务器两块磁盘,一块是用于安装系统,一块是用于GlusterFS. 192.168.10.239 GlusterFS-m ...
- yum搭建 Lamp环境
yum搭建Lamp yum install -y httpd yum install -y nano rpm 安装 Php7 相应的 yum源 rpm -Uvh https://dl.fedorapr ...
- VUE插件总结
亲们支持我的新博客哦==>地址(以后更新会尽量在新博客更新,欢迎大家访问加入我的后宫w) ) UI组件 element - 饿了么出品的Vue2的web UI工具套件 Vux - 基于Vue和W ...
- omniPlan密匙
密钥所有者都是youliyuan.OmniPlan 3:HOMJ-QOJH-OIBN-TNIH-HWUN-TEEH-WUNNKWO-HVKB-JAZE-UIHH-XAVY-BEEX-AVYBCRW-M ...
- sql脚本过大,无法打开的解决方法
打开cmd命令窗口,输入如下命令: sqlcmd -S ipaddress -U user -P password -d dbname -i file 其中,ipaddress是数据库服务器ip,us ...
- Revit 命令添加下拉框
在学习revit制作下拉框时,需要分为三个步骤: 1.创建一个面板(panel). RibbonPanel panel10 = application.CreateRibbonPanel(Global ...
- Ubuntu忘记超级用户root密码,重新设置密码
Ubuntu版本:Ubuntu 16.04.3 LTS 1启动系统,在启动过程中,反复按Esc键或者shift键(本人亲测反复按或者长按都可以,没必要纠结),直到出现以下界面: 通过上下键移动,选择U ...
- 海外aws-ubuntu-16.04系统使用ansible安装tidb
本以为按照官方文档会比较顺利,没想到还是遇到了几个坑,毕竟pingcap不能考虑到所有问题 环境: 1.ubuntu:16.04LTS 2.python:2.7 小坑:因为第一次使用ubuntu,没想 ...
- 线程之Callable、Future 和FutureTask使用及源码分析
一.Callable 我们知道启动线程有以下两种方式(jdk源码注释中官方定义只有两种启动方式,callable不算线程启动方式) 原文链接:http://www.studyshare.cn/blog ...
- pytorch 生成随机数
在使用PyTorch做实验时经常会用到生成随机数Tensor的方法,比如: torch.rand() torch.randn() torch.normal() torch.linespace() 在很 ...