为什么 AbstractOwnableSynchronizer.exclusiveOwnerThread 没有声明为 volatile?
Why AbstractOwnableSynchronizer.exclusiveOwnerThread is not declared as volatile?
在阅读java.util.concurrent.locks.ReentrantLock
的源代码时,我发现tryLock()
方法的实现如下:
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;
}
我们尝试“拥有”锁或检查我们是否已经拥有锁,这取决于AbstractQueuedSynchronizer
中维护的state
。但我想知道为什么变量 state
声明为 volatile 而变量 exclusiveOwnerThread
不是?
要理解为什么 exclusiveOwnerThread
不需要易失性,将获取和释放方法放在一起会有所帮助。
获取方式1:
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
@ReservedStackAccess
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;
}
发布方式:
@ReservedStackAccess
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;
}
同样重要的是要认识到 exclusiveOwnerThread
没有引用一些与所涉及的线程无关的任意对象。它专门持有对 Thread
实例的引用,并与调用线程进行严格比较。换句话说,重要的是如果:
Thread.currentThread() == getExclusiveOwnerThread()
当且仅当调用线程先前以自身作为参数调用了 #setExclusiveOwnerThread(Thread)
时,由于 #nonfairTryAcquire(int)
和 #tryRelease(int)
的组合性质,这才是正确的.一个线程中的操作始终发生在 同一线程中的后续操作之前。
所以如果c != 0
那么有两种情况:
调用线程拥有同步器。
- 由于一个线程中的操作总是先于同一线程中的后续操作,因此保证
getExclusiveOwnerThread()
将return引用调用线程.
调用线程不拥有同步器。
getExclusiveOwnerThread()
编辑了什么参考不再重要,因为 不可能 [=80] =] 对调用线程的引用。
由于 #tryRelease(int)
中的 setExclusiveOwnerThread(null)
调用,调用线程永远看不到对自身的过时引用。这意味着 getExclusiveOwnerThread()
可以 return null
或其他一些 Thread
引用(陈旧与否),但绝不是对调用线程的引用。
state
必须是易变的原因是因为它在线程之间以一种最重要的方式共享,每个线程都能看到最新的值。
1. FairSync#tryAcquire(int)
的实现与实现几乎相同,只是它考虑了调用线程的顺序。
在阅读java.util.concurrent.locks.ReentrantLock
的源代码时,我发现tryLock()
方法的实现如下:
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;
}
我们尝试“拥有”锁或检查我们是否已经拥有锁,这取决于AbstractQueuedSynchronizer
中维护的state
。但我想知道为什么变量 state
声明为 volatile 而变量 exclusiveOwnerThread
不是?
要理解为什么 exclusiveOwnerThread
不需要易失性,将获取和释放方法放在一起会有所帮助。
获取方式1:
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
@ReservedStackAccess
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;
}
发布方式:
@ReservedStackAccess
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;
}
同样重要的是要认识到 exclusiveOwnerThread
没有引用一些与所涉及的线程无关的任意对象。它专门持有对 Thread
实例的引用,并与调用线程进行严格比较。换句话说,重要的是如果:
Thread.currentThread() == getExclusiveOwnerThread()
当且仅当调用线程先前以自身作为参数调用了 #setExclusiveOwnerThread(Thread)
时,由于 #nonfairTryAcquire(int)
和 #tryRelease(int)
的组合性质,这才是正确的.一个线程中的操作始终发生在 同一线程中的后续操作之前。
所以如果c != 0
那么有两种情况:
调用线程拥有同步器。
- 由于一个线程中的操作总是先于同一线程中的后续操作,因此保证
getExclusiveOwnerThread()
将return引用调用线程.
- 由于一个线程中的操作总是先于同一线程中的后续操作,因此保证
调用线程不拥有同步器。
getExclusiveOwnerThread()
编辑了什么参考不再重要,因为 不可能 [=80] =] 对调用线程的引用。由于
#tryRelease(int)
中的setExclusiveOwnerThread(null)
调用,调用线程永远看不到对自身的过时引用。这意味着getExclusiveOwnerThread()
可以 returnnull
或其他一些Thread
引用(陈旧与否),但绝不是对调用线程的引用。
state
必须是易变的原因是因为它在线程之间以一种最重要的方式共享,每个线程都能看到最新的值。
1. FairSync#tryAcquire(int)
的实现与实现几乎相同,只是它考虑了调用线程的顺序。