1)、ReentrantLock.tryLock
//获取没有被其他线程持有的锁
//1)、当没有被任何线程持有时,首先将计数器设置为1,并设置当前持有锁的线程为当前线程,最后返回true
//2)、当被当前线程持有时,将计数器加1,最后返回true;
//3)、否则返回false
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
} //接着直接调用抽象类中的Sync.nonfairTryAcquire
final boolean nonfairTryAcquire(int acquires) {
//获取当前调用线程
final Thread current = Thread.currentThread();
//获取当前锁的状态,也就是当前锁的计数器的数值
int c = getState();
if (c == 0) {
//此时说明,当前锁没有被任何线程持有
if (compareAndSetState(0, acquires)) {
//使用CAS操作,更新锁的状态,即锁的计数器的数值,若是成功,则将当前锁的线程持有者设置为当前线程
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
//根据JMM模型可知,同一个工作内存内是可见的,故同一个线程内是可见的,若相等,是同一个线程,且在同一个线程内不会发生setExclusiveOwnerThread时,在getExclusiveOwnerThread得到的不一样
//此时说明,当前锁的线程持有者是当前线程
//设置锁的计数器的值
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
//更新锁的状态,即锁的计数值的数值
setState(nextc);
return true;
}
return false;
} 2)、ReentrantLock.unlock
//试图释放锁
//1)、当前线程不是该锁的持有者时,抛出异常
//2)、当前锁的计数器更改为0时,则设置当前锁的持有者为null
//3)、否则,更新当前锁的状态,即锁的计数器的数值
public void unlock() {
sync.release(1);
} //接着直接调用抽象类AbstractQueuedSynchronizer.release
public final boolean release(int arg) {
if (tryRelease(arg)) {
//当锁的状态为0,或者说当前锁没有持有者时,需要唤醒当前锁上挂起的线程
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
} //再接着直接调用抽象类Sync.tryRelease
protected final boolean tryRelease(int releases) {
//计算当前锁的计数器的数值
int c = getState() - releases;
//判断当前线程是否是锁的持有者,若不是,则抛出异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
//当计数器的数值为0,说明此时锁没有持有者了,故先更新线程持有者,之后再去更新锁的状态,这样当去获取锁的状态时,此时的锁的持有者必然是更新后的,这样锁的释放和锁的获取就能保证一致的可见性了。
free = true;
setExclusiveOwnerThread(null);
}
//更新锁的状态,即锁的计数器的数值
setState(c);
return free;
} //直接调用AbstractQueuedSynchronizer.unparkSuccessor
//唤醒当前节点后的第一个非取消节点中的线程
private void unparkSuccessor(Node node) { //尝试更新当前节点的状态
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0); //获取当前节点后的第一个非取消节点,并唤醒该节点中挂起的线程
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
//从尾节点开始查找,直到当前节点,即可得到一个当前节点后的第一个非取消节点
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
} //唤醒线程
if (s != null)
LockSupport.unpark(s.thread);
} 3)、ReentrantLock.lock
//申请锁
public void lock() {
sync.lock();
} 31)、非公平锁
//直接调用NonfairSync.lock
final void lock() {
//当通过CAS判断当前锁是否没有持有者,若是,则直接设置当前锁的持有者为当前线程;
//否则,再次尝试加锁,最后还不成功,就如等待队列,线程挂起,直到被唤醒为止
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
} //直接调用AbstractQueuedSynchronizer.acquire
public final void acquire(int arg) {
//尝试获取非公平锁,当失败时,就将当前线程入等待队列,线程挂起,直到被挂起
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
} //直接调用NonfairSync.tryAcquire
protected final boolean tryAcquire(int acquires) {
//尝试获取非公平锁
return nonfairTryAcquire(acquires);
} //直接调用AbstractQueuedSynchronizer.addWaiter
//将排他锁节点添加到链表尾部
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) {
//当前链表已经初始化,则CAS尝试将排他锁节点更改为链表的尾节点 //设置当前节点的前一个节点为当前链表的尾节点
node.prev = pred;
//当CAS尝试更新尾节点成功,则将新尾节点的前一个节点的下一个节点更新为新的尾节点
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
} //直接调用AbstractQueuedSynchronizer.compareAndSetTail
//原子更新链表的尾节点
private final boolean compareAndSetTail(Node expect, Node update) {
return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
} //直接调用AbstractQueuedSynchronizer.enq
//使用CAS原子性将节点插入到链表尾部
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;
//当CAS尝试更新尾节点成功,则将新尾节点的前一个节点的下一个节点更新为新的尾节点
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
} //直接调用AbstractQueuedSynchronizer.acquireQueued
//当当前节点为等待队列中的第一个节点时,获取到锁
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
//当当前节点的前节点为头结点,并为当前线程尝试获取锁,成功时,设置当前节点为头结点,并将当前节点的前节点的下一个节点取消,使之没有被引用,这样可以被GC回收
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);
}
} //直接调用AbstractQueuedSynchronizer.setHead
//设置当前节点为头结点,并将当前节点的前节点置为空,以及将当前节点持有的线程设置为空
private void setHead(Node node) {
head = node;
node.thread = null;
node.prev = null;
} //直接调用AbstractQueuedSynchronizer.shouldParkAfterFailedAcquire
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
//当当前节点的前节点状态为唤醒时,则表明下一个被执行的节点是当前节点,即线程会被唤醒
return true;
if (ws > 0) {
//当当前节点的前节点为取消的节点,则往前查找一个非取消的节点
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
//将查找的非取消节点的下一个节点更新为当前节点
pred.next = node;
} else {
//尝试将当前节点的前节点的状态设置为唤醒状态
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
} //直接调用AbstractQueuedSynchronizer.compareAndSetWaitStatus
//尝试更新节点的状态
private static final boolean compareAndSetWaitStatus(Node node, int expect, int update) {
return unsafe.compareAndSwapInt(node, waitStatusOffset, expect, update);
} //直接调用AbstractQueuedSynchronizer.parkAndCheckInterrupt
//将当前线程挂起
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
Semaphore:资源控制,是线程同步的工具类,默认是公平策略;如停车场,最多只有100个车位,故当满时,只能出一个之后,才能进一个;
当新建时,需指定控制的资源的个数,即同时进行的线程数,还有就是使用的是公平还是非公平的策略,默认是非公平;
acquire获取资源;
release释放资源; CountDownLatch:满足条件时触发;如赛跑,在开始前,所有运动员准备好之后,才能开始;当所有运动员到达终点时,才能结束;还如,当获取专辑的所有视频资源信息时,只有所有的视频信息获取到之后,才能进行之后的操作;当新建时,需要指定锁计数的个数; await:等待锁计数为0,之前一直阻塞
countDown:递减计数器的计数,如果计数达到0,则释放所有等待的线程; 实际操作都是由其属性Sync来进行,且该属性对象继承了AbstractQueuedSynchronizer类; 参考资料:
http://www.itzhai.com/the-introduction-and-use-of-a-countdownlatch.html
http://mouselearnjava.iteye.com/blog/1921468

ReentrantLock源码了解的更多相关文章

  1. Java并发系列[5]----ReentrantLock源码分析

    在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可 ...

  2. Java并发编程笔记之ReentrantLock源码分析

    ReentrantLock是可重入的独占锁,同时只能有一个线程可以获取该锁,其他获取该锁的线程会被阻塞后放入该锁的AQS阻塞队列里面. 首先我们先看一下ReentrantLock的类图结构,如下图所示 ...

  3. Java并发编程-ReentrantLock源码分析

    一.前言 在分析了 AbstractQueuedSynchronier 源码后,接着分析ReentrantLock源码,其实在 AbstractQueuedSynchronizer 的分析中,已经提到 ...

  4. 第六章 ReentrantLock源码解析2--释放锁unlock()

    最常用的方式: int a = 12; //注意:通常情况下,这个会设置成一个类变量,比如说Segement中的段锁与copyOnWriteArrayList中的全局锁 final Reentrant ...

  5. java多线程---ReentrantLock源码分析

    ReentrantLock源码分析 基础知识复习 synchronized和lock的区别 synchronized是非公平锁,无法保证线程按照申请锁的顺序获得锁,而Lock锁提供了可选参数,可以配置 ...

  6. ReentrantLock源码分析--jdk1.8

    JDK1.8 ArrayList源码分析--jdk1.8LinkedList源码分析--jdk1.8HashMap源码分析--jdk1.8AQS源码分析--jdk1.8ReentrantLock源码分 ...

  7. 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁

    问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...

  8. JUC AQS ReentrantLock源码分析

    警告⚠️:本文耗时很长,先做好心理准备,建议PC端浏览器浏览效果更佳. Java的内置锁一直都是备受争议的,在JDK1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6 ...

  9. java源码-ReentrantLock源码分析-1

    ReentrantLock 继承于lock是比较常用的独占锁,接下来我们来分析一下ReentrantLock源码以及接口设计: Sync是ReentrantLock的内部静态抽象类继承Abstract ...

  10. ReentrantLock 源码分析从入门到入土

    回答一个问题 在开始本篇文章的内容讲述前,先来回答我一个问题,为什么 JDK 提供一个 synchronized 关键字之后还要提供一个 Lock 锁,这不是多此一举吗?难道 JDK 设计人员都是沙雕 ...

随机推荐

  1. python 喜马拉雅 音乐下载 演示代码

    1.主程序文件 import os import json import requests from contextlib import closing from progressbar import ...

  2. jquery的几种ajax方式对比

    jquery的几种ajax方式对比 jquery的ajax方式有如下几种: 1.   $.post(url,params,callback); 2.   $.getJSON(url,params,ca ...

  3. Web安全测试-WebScarab

    [功能] WebScarab是一个用来分析使用HTTP和HTTPS协议的应用程序框架.其原理很简单,WebScarab可以记录它检测到的会话内容(请求和应答),并允许使用者可以通过多种形式来查看记录. ...

  4. springboot整合rabbirmq(3.7.9)中使用mandatory参数获取匹配失败的消息以及存入rabbitmq备份交换器中!

    先说下这个参数的作用: /** * Mandatory为true时,消息通过交换器无法匹配到队列会返回给生产者 * 为false时,匹配不到会直接被丢弃 */在一些特定场景下还是有用处的!接下来说一下 ...

  5. Android 7.0 新增功能和api

    Android 7.0 Nougat 为用户和开发者引入多种新功能.本文重点介绍面向开发者的新功能. 请务必查阅 Android 7.0 行为变更以了解平台变更可能影响您的应用的领域. 要详细了解 A ...

  6. express-partials使用方法

    1.安装express-partials 方法一:运行cmd用npm install express-partials 方法二:在package.json里面的dependencies添加" ...

  7. CSS之:active选择器

    Active的一段话 active的英文解释为“积极的”,表现在鼠标上就是点击的意思.关于active选择器最多的示例恐怕就是应用在链接上面的,然而打开链接是一个一瞬间的动作,这不能很好的体现acti ...

  8. ExpressMapper- The New .NET Mapper!

    推荐,据测试比手工映射的效率还高. https://www.codeproject.com/Tips/1009198/Expressmapper-The-New-NET-Mapper

  9. .NetCore 分布式日志收集Exceptionless 在Windows下本地安装部署及应用实例

    自己安装时候遇到很多问题,接下来把这些问题写出来希望对大家有所帮助 搭建环境: 1.下载安装 java 8 SDK (不要安装最新的10.0) 并配置好环境变量(环境变量的配置就不做介绍了) 2.下载 ...

  10. Z字形变换

    将字符串 "PAYPALISHIRING" 以 Z 字形排列成给定的行数: P A H N A P L S I I G Y I R 之后从左往右,逐行读取字符:"PAHN ...