Dar*_*zAc 9 java concurrency multithreading synchronization memory-barriers
我在"实践中的Java并发"第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;
}
Run Code Online (Sandbox Code Playgroud)
我相信这是对简化代码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;
}
Run Code Online (Sandbox Code Playgroud)
因此,令人困惑的部分是如何在其他线程中看到设置owner,它只是一个普通的实例变量.实际上,读取是在调用(并且是一个合格的变量)之后,但是在设置之后,根本就没有(可以施加同步语义).数据竞争发生了?AbstractOwnableSynchronizerelse if (current == owner)ownergetState()statevolatileAQSowner
好吧,鉴于本书的权威性和经过彻底测试的代码,我想到了两种可能性:
设置之前的完整屏障(无论是mfence还是'lock'ed指令)owner = current执行隐藏的工作.但是从我从几篇着名的文章中学到的,完整的屏障更关心它之前的写作以及它之后的读取.好吧,如果这种可能性成立,那么"JCIP"中的一些句子可能会被不适当地陈述.
我注意到'地理位置' setState(c+1)确实owner = current在代码片段中出现,尽管它位于if-else的另一个分支中.如果评论说的是事实,是否意味着插入的障碍setSate(c+1)可以owner = current在另一个分支中强加同步语义?
我是这方面的新手,几个很棒的博客帮助我理解了JVM的基础(没有排序):
以及永远的宏伟:http://g.oswego.edu/dl/jmm/cookbook.html
做完作业和搜索互联网后,我得不到令人满意的结论.
请原谅我,如果这太冗长或不清楚(英语不是我的母语).请帮助我,相关的任何事情表示赞赏.
owner = current;您怀疑(在 CAS 之后)和if (current == owner)(在读取状态并检查状态是否 >0 之后)之间可能存在竞争。
单独考虑这段代码,我认为你的推理是正确的。tryRelease但是,您还需要考虑:
123: protected final boolean tryRelease(int releases) {
124: int c = getState() - releases;
125: if (Thread.currentThread() != getExclusiveOwnerThread())
126: throw new IllegalMonitorStateException();
127: boolean free = false;
128: if (c == 0) {
129: free = true;
130: setExclusiveOwnerThread(null);
131: }
132: setState(c);
133: return free;
134: }
Run Code Online (Sandbox Code Playgroud)
这里所有者null在状态设置为 0 之前被设置为 。要最初获取锁,状态必须为 0,因此所有者为null。
最后,
if (current == owner)到达c=1,
null,这也很好。 if (current == owner)到达c>1,
我同意 JCIP 中的脚注“仅在调用 getState 后读取所有者字段并仅在调用 setState 之前写入它”具有误导性。它写了ownerbefore 调用setState,tryRelease但没有tryAcquire。
| 归档时间: |
|
| 查看次数: |
934 次 |
| 最近记录: |