《java.util.concurrent 包源码阅读》03 锁
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100];
int putptr, takeptr, count; public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
} public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
public interface ReadWriteLock {
/**
* Returns the lock used for reading.
*
* @return the lock used for reading.
*/
Lock readLock(); /**
* Returns the lock used for writing.
*
* @return the lock used for writing.
*/
Lock writeLock();
}
public static void parkNanos(long nanos)
public static void parkUntil(long deadline)
public static void parkNanos(Object blocker, long nanos)
public static void parkUntil(Object blocker, long deadline)
protected boolean tryRelease(int arg)
protected int tryAcquireShared(int arg)
protected boolean tryReleaseShared(int arg)
前线程尝试获取锁的时候,AbstractQueuedSynchronizer会先调用tryAcquire或者tryAcquireShared来尝
试获取,如果得到false,那么把当前线程放到等待队列中去,然后再做进一步操作。我们来分析以下6种情况,前三种用于独占锁,后三者用于共享,独占锁
或者共享锁按照等待方式又分为三种:不可中断线程等待,可中断线程等待,尝试限时等待超时放弃。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
final boolean acquireQueued(final Node node, int arg) {
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
//检测自己是否已经排到第一个了
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return interrupted;
}
//shouldParkAfterFailedAcquire的作用检测我是不是需要安心地等,如果是的话,
//就调用parkAndCheckInterrupt进入等待,等待结束后会返回线程是否已经中断
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} catch (RuntimeException ex) {
cancelAcquire(node);
throw ex;
}
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
//SIGNAL的意思就是说前面那个家伙在释放锁以后会告诉我的,我安心等就是了
return true;
if (ws > 0) {
/*
* ws大于0的意思就是这个Node已经被取消了,需要跳过,并且从队列中清除出去
* 这里会清除我前面所有这种类型的Node
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
* 这里ws是0或者PROPAGATE,表示他是傻乎乎的家伙,还不知道SIGNAL规则
* 0是独占锁,PROPAGATE是共享锁,compareAndSetWaitStatus会找人把他设成SIGNAL
* 状态,(成功与否未知,所以返回false)参见上面关于SIGNAL的解释
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
public final void acquireInterruptibly(long arg) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
private void doAcquireInterruptibly(long arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
break;
}
} catch (RuntimeException ex) {
cancelAcquire(node);
throw ex;
}
// Arrive here only if interrupted
cancelAcquire(node);
throw new InterruptedException();
}
private boolean doAcquireNanos(long arg, long nanosTimeout)
throws InterruptedException {
long lastTime = System.nanoTime();
final Node node = addWaiter(Node.EXCLUSIVE);
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return true;
}
if (nanosTimeout <= 0) {
cancelAcquire(node);
return false;
} // 多次parkNanos,计算实际耗费的时间才是安全的做法
if (nanosTimeout > spinForTimeoutThreshold &&
shouldParkAfterFailedAcquire(p, node))
LockSupport.parkNanos(this, nanosTimeout);
long now = System.nanoTime();
nanosTimeout -= now - lastTime;
lastTime = now; // 如果线程被中断,不好意思,要抛出异常的
if (Thread.interrupted())
break;
}
} catch (RuntimeException ex) {
cancelAcquire(node);
throw ex;
}
// Arrive here only if interrupted
cancelAcquire(node);
throw new InterruptedException();
}
private void setHeadAndPropagate(Node node, long propagate) {
Node h = head; // Record old head for check below
setHead(node);
/*
* Try to signal next queued node if:
* Propagation was indicated by caller,
* or was recorded (as h.waitStatus) by a previous operation
* (note: this uses sign-check of waitStatus because
* PROPAGATE status may transition to SIGNAL.)
* and
* The next node is waiting in shared mode,
* or we don't know, because it appears null
*
* The conservatism in both of these checks may cause
* unnecessary wake-ups, but only when there are multiple
* racing acquires/releases, so most need signals now or soon
* anyway.
*/
if (propagate > 0 || h == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared();
}
}
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;
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (isFirst(current) &&
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;
}
}
final boolean isFirst(Thread current) {
Node h, s;
return ((h = head) == null ||
((s = h.next) != null && s.thread == current) ||
fullIsFirst(current));
}
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
/*
* Note that tryRelease and tryAcquire can be called by
* Conditions. So it is possible that their arguments contain
* both read and write holds that are all released during a
* condition wait and re-established in tryAcquire.
*/ protected final boolean tryRelease(int releases) {
int nextc = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
// 首先检查独占锁计数,如果是0表示独占锁已经被完全释放,则清除独占锁线程
// 更新状态
if (exclusiveCount(nextc) == 0) {
setExclusiveOwnerThread(null);
setState(nextc);
return true;
} else {
setState(nextc);
return false;
}
} protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
* 1. if read count nonzero or write count nonzero
* and owner is a different thread, fail.
* 2. If count would saturate, fail. (This can only
* happen if count is already nonzero.)
* 3. Otherwise, this thread is eligible for lock if
* it is either a reentrant acquire or
* queue policy allows it. If so, update state
* and set owner.
*/
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 0) {
// c != 0表示有共享锁或者独占锁存在,w == 0表示没有独占锁
// 那么两个条件同时成立表示有共享锁存在,就无法获得独占锁
// 或者有线程拥有独占锁但不是当前线程,那也无权获得独占锁
// (Note: if c != 0 and w == 0 then shared count != 0)
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
}
// 到了这一步,可能有以下几种情况:
// 1) c == 0没有任何锁存在(这个时候 w == 0 也成立)
// 2) 当前线程拥有独占锁,并且还没到锁的最大限制数 // w == 0是当前线程没有独占锁,属于新申请
// writerShouldBlock是抽象方法,对于FairSync和UnfairSync有不同实现
// 该发现检查当前线程申请独占锁应不应该被阻止
// 对于FairSync,writerShouldBlock会用isFirst检查,
// 对于isFirst,如果如果没人排队,或者你是第一个排队的,或者fullIsFirst就返回true
// 对于fullIsFirst,不是很理解
// 对于UnfairSync,writerShouldBlock永远返回false,因为没有排队的概念(体现Unfair)
if ((w == 0 && writerShouldBlock(current)) ||
!compareAndSetState(c, c + acquires))
return false; // 获取独占锁成功,设置独占锁线程
setExclusiveOwnerThread(current);
return true;
} // 这里使用HoldCounter类型的ThreadLocal变量存储当前线程拥有的共享锁的计数
// cachedHoldCounter缓存最近一次成功获取共享锁的线程的ThreadLocal变量
protected final boolean tryReleaseShared(int unused) {
HoldCounter rh = cachedHoldCounter;
Thread current = Thread.currentThread();
if (rh == null || rh.tid != current.getId())
rh = readHolds.get();
// tryDecrement()返回拥有的共享锁的计数,大于0则并且更新计数(减1)。
if (rh.tryDecrement() <= 0)
throw new IllegalMonitorStateException(); // 更新共享锁的计数
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT; // 高位的共享锁计数减一
if (compareAndSetState(c, nextc))
return nextc == 0;
}
} protected final int tryAcquireShared(int unused) {
/*
* Walkthrough:
* 1. If write lock held by another thread, fail
* 2. If count saturated, throw error
* 3. Otherwise, this thread is eligible for
* lock wrt state, so ask if it should block
* because of queue policy. If not, try
* to grant by CASing state and updating count.
* Note that step does not check for reentrant
* acquires, which is postponed to full version
* to avoid having to check hold count in
* the more typical non-reentrant case.
* 4. If step 3 fails either because thread
* apparently not eligible or CAS fails,
* chain to version with full retry loop.
*/
Thread current = Thread.currentThread();
int c = getState();
// 其他线程正在使用独占锁
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
// 共享锁计数到达最大限制
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded"); // 类似于writerShouldBlock,readerShouldBlock是抽象方法,有不同实现,
// 检查是不是阻止当前线程共享锁的申请
// 对于UnfairSync,为了防止独占锁饿死的情况,如果发现队列中第一个排队的是独占锁申请,
// 就是block当前共享锁的申请
// 对于FairSync,同样使用isFirst检查当前线程
if (!readerShouldBlock(current) &&
compareAndSetState(c, c + SHARED_UNIT)) {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != current.getId())
cachedHoldCounter = rh = readHolds.get();
rh.count++;
return 1;
} // 针对CAS失败或者一些不太常见的失败的情况
// 思想:实现常规版本和完整版本(包含所有情况),在常规版本失败的情况下调用完整版本, 提高效率
return fullTryAcquireShared(current);
}
/**
* Full version of acquire for reads, that handles CAS misses
* and reentrant reads not dealt with in tryAcquireShared.
*/
final int fullTryAcquireShared(Thread current) {
/*
* This code is in part redundant with that in
* tryAcquireShared but is simpler overall by not
* complicating tryAcquireShared with interactions between
* retries and lazily reading hold counts.
*/
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != current.getId())
rh = readHolds.get();
for (;;) {
int c = getState();
int w = exclusiveCount(c);
// 红色部分表示没有占用共享锁,新申请共享锁
if ((w != 0 && getExclusiveOwnerThread() != current) ||
((rh.count | w) == 0 && readerShouldBlock(current)))
return -1;
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {
cachedHoldCounter = rh; // cache for release
rh.count++;
return 1;
}
}
}
《java.util.concurrent 包源码阅读》03 锁的更多相关文章
- 《java.util.concurrent 包源码阅读》 结束语
<java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...
- 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分
这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...
- 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包
Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...
- 《java.util.concurrent 包源码阅读》04 ConcurrentMap
Java集合框架中的Map类型的数据结构是非线程安全,在多线程环境中使用时需要手动进行线程同步.因此在java.util.concurrent包中提供了一个线程安全版本的Map类型数据结构:Concu ...
- 《java.util.concurrent 包源码阅读》17 信号量 Semaphore
学过操作系统的朋友都知道信号量,在java.util.concurrent包中也有一个关于信号量的实现:Semaphore. 从代码实现的角度来说,信号量与锁很类似,可以看成是一个有限的共享锁,即只能 ...
- 《java.util.concurrent 包源码阅读》06 ArrayBlockingQueue
对于BlockingQueue的具体实现,主要关注的有两点:线程安全的实现和阻塞操作的实现.所以分析ArrayBlockingQueue也是基于这两点. 对于线程安全来说,所有的添加元素的方法和拿走元 ...
- 《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇
concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void ...
- 《java.util.concurrent 包源码阅读》05 BlockingQueue
想必大家都很熟悉生产者-消费者队列,生产者负责添加元素到队列,如果队列已满则会进入阻塞状态直到有消费者拿走元素.相反,消费者负责从队列中拿走元素,如果队列为空则会进入阻塞状态直到有生产者添加元素到队列 ...
- 《java.util.concurrent 包源码阅读》10 线程池系列之AbstractExecutorService
AbstractExecutorService对ExecutorService的执行任务类型的方法提供了一个默认实现.这些方法包括submit,invokeAny和InvokeAll. 注意的是来自E ...
随机推荐
- 【JDK1.8】JDK1.8集合源码阅读——总章
一.前言 今天开始阅读jdk1.8的集合部分,平时在写项目的时候,用到的最多的部分可能就是Java的集合框架,通过阅读集合框架源码,了解其内部的数据结构实现,能够深入理解各个集合的性能特性,并且能够帮 ...
- 【转】open参数O_DIRECT的学习
open参数O_DIRECT的学习 使用 O_DIRECT 需要注意的地方 posix_memalign详细解释 free:这里好几个方法我都没测试成功,最后还是用posix_memalign 对齐的 ...
- LeetCode 448. Find All Numbers Disappeared in an Array (在数组中找到没有出现的数字)
Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and ot ...
- Java多线程高并发学习笔记——阻塞队列
在探讨可重入锁之后,接下来学习阻塞队列,这边篇文章也是断断续续的写了很久,因为最近开始学ssm框架,准备做一个自己的小网站,后续可能更新自己写网站的技术分享. 请尊重作者劳动成果,转载请标明原文链接: ...
- iOS 之 protocol的相关问题
定义一个协议, 一个协议可以扩展子另一个协议 如果需要扩展多个协议中间使用逗号分隔 //定义一个协议 @protocol AnimalDelegate <NSObject, ***> @r ...
- Linux 源码编译Python 3.6
Linux 源码编译Python 3.6 1.操作系统以及版本显示 # uname -sr Linux 3.10.0-514.el7.x86_64 # uname -sr Linux 3.10.0-5 ...
- A strange lift
Problem Description There is a strange lift.The lift can stop can at every floor as you want, and th ...
- Fibonacci Check-up
Fibonacci Check-up Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- C++求出旋转数组的最小数字
今天遇到这么一道题目,感觉很有意思,要记下来! 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4 ...
- c++学习笔记---04---从另一个小程序接着说
从另一个小程序接着说 文件I/O 前边我们已经给大家简单介绍和演示过C和C++在终端I/O处理上的异同点. 现在我们接着来研究文件I/O. 编程任务:编写一个文件复制程序,功能实现将一个文件复制到另一 ...