我在“Java Concurrency in Practice”第 14.6.1 节中阅读了 ReentrantLock 实现的一些细节,注释中的某些内容让我感到困惑:
因为受保护的状态操作方法具有易失性读取或写入的内存语义,并且 ReentrantLock仅在调用 getState 后仔细读取所有者字段并仅在调用 setState 之前写入,所以 ReentrantLock 可以捎带同步状态的内存语义,从而避免进一步的同步参见第 16.1.4 节。
它所指的代码:
protected boolean tryAcquire(int ignored) {
final Thread current = Thread.currentThread();
int c = getState();
if (c ==0) {
if (compareAndSetState(0, 1)) {
owner = current;
return true;
}
} else if (current == owner) {
setState(c+1);
return true;
}
return false;
}
我相信这nonfairTryAcquire
是ReentrantLock.Sync
.
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;
}
因此,令人困惑的部分是 的设置(owner
它只是 中的普通实例变量)如何在其他线程中AbstractOwnableSynchronizer
变得可见。确实,在调用 之后else if (current == owner)
读取(并且是 的限定变量),但是在设置 之后,根本没有任何东西(可以施加同步语义)。数据竞赛发生了吗?owner
getState()
state
volatile
AQS
owner
好吧,鉴于本书的权威性和经过彻底测试的代码,我想到了两种可能性:
owner = current
设置执行隐藏工作之前的完整障碍(无论是 mfence 还是“锁定”指令) 。但是从我从几篇著名的文章中了解到,full barrier 更关心它之前的写入以及之后的读取。好吧,如果这种可能性成立,那么“JCIP”中的某些句子可能会被不当陈述。我注意到代码片段中的“地理上”
setState(c+1)
确实出现在后面,尽管它位于 if-else 的另一个分支中。owner = current
如果评论说的是真的,这是否意味着插入的屏障可以在另一个分支setSate(c+1)
上施加同步语义?owner = current
我是这个领域的新手,一些很棒的博客帮助我理解了 JVM 的底层(无排序):
- http://mechanical-sympathy.blogspot.com/
- http://preshing.com/
- http://bartoszmilewski.com
- http://psy-lob-saw.blogspot.com/
以及总是宏伟的:http: //g.oswego.edu/dl/jmm/cookbook.html
在做完功课和搜索互联网后,我未能得出令人满意的结论。
如果这太罗嗦或不清楚,请原谅我(英语不是我的母语)。请帮我解决这个问题,任何相关的事情都会受到赞赏。