接下来跟着上一篇, 解析情景五和情景六
情景五
写读读
public static void main(String[] args){
final Printer printer = new Printer();
Thread thread1 = new Thread(){
@Override
public void run() {
try {
printer.write("test1");
} catch (Exception e) {
e.printStackTrace();
}
}
};
Thread thread2 = new Thread(){
@Override
public void run() {
try {
printer.read("test2");
} catch (Exception e) {
e.printStackTrace();
}
}
};
Thread thread3 = new Thread(){
@Override
public void run() {
try {
printer.read("test3");
} catch (Exception e) {
e.printStackTrace();
}
}
};
thread1.start();
thread2.start();
thread3.start();
}
public void lock() {
sync.acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
// thread-0
Thread current = Thread.currentThread();
// c = 0
int c = getState();
// w = 0
int w = exclusiveCount(c);
// 不走此分支
if (c != 0) {
......
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
static final class FairSync extends Sync {
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
}
public final boolean hasQueuedPredecessors() {
Node t = tail;
Node h = head;
Node s;
// h和t都为null, 返回false
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
回到tryAcquire方法
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 0) {
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
setState(c + acquires);
return true;
}
// writerShouldBlock方法返回false
if (writerShouldBlock() ||
// 在此CAS假设是成功的
// 所以不会走此分支
!compareAndSetState(c, c + acquires))
return false;
// 设置获得写锁的线程为thread-0
setExclusiveOwnerThread(current);
// 返回true
return true;
}
此时线程1获得写锁, 线程2开始执行
public void lock() {
sync.acquireShared(1);
}
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
protected final int tryAcquireShared(int unused) {
// thread-1
Thread current = Thread.currentThread();
// c = 1
int c = getState();
// 此时线程1获得写锁
// 并且当前线程是线程2
// 所以会进入此分支
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
......
}
接下来回到acquireShared方法
public final void acquireShared(int arg) {
// tryAcquireShared返回-1, 进入此分支
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
private void doAcquireShared(int arg) {
// 向队列中加入代表当前线程的节点
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 线程2是第一个被阻塞的
// 所以其前序节点就是head
// p此时就是head
final Node p = node.predecessor();
if (p == head) {
// 在进行阻塞或其他操作前再确认下是否可以获得锁
// 此时r = -1, 也就是确实无法获取到锁
int r = tryAcquireShared(arg);
// 不走此分支
if (r >= 0) {
......
}
}
// 第一次循环不会阻塞, 第二次循环会被阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
此时线程2就被阻塞
此时, 线程3开始执行
// ReadLock
public void lock() {
sync.acquireShared(1);
}
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
protected final int tryAcquireShared(int unused) {
// thread-2
Thread current = Thread.currentThread();
// c = 1
int c = getState();
// 获得锁线程为thread-0, 进入此分支
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
......
}
回到acquireShared方法
public final void acquireShared(int arg) {
// tryAcquireShared返回-1, 进入此分支
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
private void doAcquireShared(int arg) {
// 此时将thread-2加入队列尾部
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
// p代表被阻塞的线程thread-1, 不是head
// 不走此分支
if (p == head) {
......
}
// 在第二次循环的时候会阻塞自身
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
情景六
写读写
线程1和线程2和情景五一样, 主要解析线程3
public void lock() {
sync.acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
// thread-2
Thread current = Thread.currentThread();
// c = 1
int c = getState();
// w = 1
int w = exclusiveCount(c);
if (c != 0) {
// 虽然w = 1
// 但是加锁线程为thread-0, 可以走此分支
if (w == 0 || current != getExclusiveOwnerThread())
return false;
......
}
...
}
接下来返回acquire方法
public final void acquire(int arg) {
// tryAcquire返回false
if (!tryAcquire(arg) &&
// 将对应当前线程的节点加入缓存队列中
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
此时线程3被阻塞
网友评论