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 的分析中,已经提到 ...
随机推荐
- CefSharp 与 js 相互调用
https://blog.csdn.net/gong_hui2000/article/details/48155547
- [STM32F103]RTC日历
使能PWR和BKP时钟: a) RCC_APB1PeriphClockCmd(); 使能后备寄存器访问: a) PWR_BackupAccessCmd(); 配置RTC时钟源,使能RTC时钟: a) ...
- Vue.js中记不住 的东西
给样式背景赋值: :style="{backgroundImage:'url(' + otherInfo.head_image + ')'}" <img :src=" ...
- thunderbird 163 smtp
thunderbird 163 smtp 如果要正常发送,配置如下: server: smtp.163.com port: 465 auth: Normal password security: SS ...
- Flutter环境搭建
本文介绍mac上搭建Flutter环境 1.Flutter官方提供中国地区镜像地址:https://github.com/flutter/flutter/wiki/Using-Flutter-in-C ...
- Slf4j与log4j及log4j2的关系及使用方法
Slf4j与log4j及log4j2的关系及使用方法 slf4j slf4j仅仅是一个为Java程序提供日志输出的统一接口,并不是一个具体的日志实现方案,就比如JDBC一样,只是一种规则而已,所以单独 ...
- nginx问题集锦
1.配置访问指定路径的文件 以访问/mnt/data/logs下文件为例,修改nginx.conf配置,执行命令重新加载/usr/local/nginx/sbin/nginx -s reload lo ...
- sys.exit(main(sys.argv[1:]))
sys.argv sys.argv[]说白了就是一个从程序外部获取参数的桥梁. 首先我们需要import sys,sys是python3的一个标准库,也就是一个官方的模块.封装了一些系统的信息和接口, ...
- hbase的常用的shell命令&hbase的DDL操作&hbase的DML操作
前言 笔者在分类中的hbase栏目之前已经分享了hbase的安装以及一些常用的shell命令的使用,这里不仅仅重新复习一下shell命令,还会介绍hbase的DDL以及DML的相关操作. hbase的 ...
- Windows、Linux的环境变量
Windows操作系统 什么是环境变量?环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数,比如临时文件夹位置和系统文件夹位置等. 这点有点类似于DOS时期的默认路径,当你运行某些程序时除 ...