private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);
private static ReentrantReadWriteLock.ReadLock rl= readWriteLock.readLock();
private static ReentrantReadWriteLock.WriteLock wl= readWriteLock.writeLock();
/**
同一个线程获取读锁后再试图获取写锁,这种情况就会出现死锁
试想一下:读锁与读锁之间不存在互斥的问题,读锁跟写锁互斥,互斥就是为了防止读数据期间临界区资源不被
修改,如果获取读锁后,同时其他线程也获取到了读锁,然后该线程试能成功获取写锁,之前的那种保护将没有意义!!
**/
private void testUpgrade(){
//获取读锁
rl.lock();
//获取读锁
wl.lock();
wl.unlock();
rl.unlock();
log.info("结束");
}
/**
下面看下获取读锁后再获取写锁死锁的地方
**/
public final void acquire(int arg) {
//tryAcquire失败后会进入acquireQueued方法,acquireQueued里面会不断调用tryAcquire方法试图获取写锁,但本文所说的情况下是不可能获得写锁的
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
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) {
// (Note: if c != 0 and w == 0 then shared count != 0)
//代码会走到这里,但是此时没有任何线程获取到写锁,所以getExclusiveOwnerThread()返回null,current线程为已经获取到试图获取写锁的线程,这里就会直接返回false,接下来就会进入acquireQueued方法
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
setState(c + acquires);
return true;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//获取写锁失败后会根据条件判断是否需要进入睡眠,本文所说的死锁最终会因调用
//parkAndCheckInterrupt方法放弃cpu资源进入睡眠模式,但是之后没有任何唤醒源,
//也就是进入了传说中的死锁
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}