[英]Do I need to use volatile?
Consider the following code:考虑以下代码:
public class MyDataStructure {
int size;
final ReentrantLock lock = new ReentrantLock();
public void update() {
lock.lock();
try {
// do coll stuff
size++;
} finally {
lock.unlock();
}
}
public int size() {
return size;
}
}
As far as I understand, ReentrantLock
imposes an happens-before relationship so size++
needs to affect the main memory and the cache (of other threads) with the new value.据我了解,
ReentrantLock
强加了先发生关系,因此size++
需要用新值影响主 memory 和缓存(其他线程)。 Hence, no need to use volatile
for size
.因此,不需要使用
volatile
作为size
。 Also, for the same reason the method size()
can simply return size
.此外,出于同样的原因,方法
size()
可以简单地返回size
。
Is my understanding correct?我的理解正确吗?
No.不。
Other threads may see a stale (old) value of size.其他线程可能会看到过时的(旧)大小值。
When other threads execute size()
there is nothing there instructing it to ensure it's not reading an old value, such as a locally cached value in another cpu cache etc. Also worth mentioning is hoisting by the jvm.当其他线程执行
size()
时,没有任何内容指示它确保它不读取旧值,例如另一个 cpu 缓存中的本地缓存值等。另外值得一提的是 jvm 的提升。
AN example, if you have a loop calling size()
in one thread, it may never exit if update()
is not called in the loop, or size changed, and called/changed from other threads only.一个例子,如果你有一个循环调用
size()
在一个线程中,如果update()
没有在循环中调用,或者大小改变,并且只从其他线程调用/改变,它可能永远不会退出。
while (size() == 0) {
...
}
The jit compiler, (at least the modern part what used to be called the c2/server compiler) could happily optimize away (hoist) the size variable checks as it sees that it never changes in the loop. jit 编译器(至少是过去称为 c2/server 编译器的现代部分)可以愉快地优化(提升)大小变量检查,因为它看到它在循环中永远不会改变。
As far as I understand, ReentrantLock imposes an happens-before relationship...
据我了解, ReentrantLock 强加了一种先发生的关系......
Yes.是的。 When some thread W (W for "writer") unlocks a lock, that "happens before" some other thread R (for "reader") subsequently locks the same lock.
当某个线程 W(W 代表“writer”)解锁一个锁时,“发生在”某个其他线程 R(代表“reader”)随后锁定同一个锁。
In order to take advantage of that relationship, you have to lock the same lock in both methods:为了利用这种关系,您必须在两种方法中锁定相同的锁:
public class MyDataStructure {
int size;
final ReentrantLock lock = new ReentrantLock();
public void update() {
lock.lock();
try {
size++; // happens before unlock() because things that happen
// in one thread all happen in _program order._
} finally {
lock.unlock(); // Happens before a pending lock.lock() call in some
// other thread.
}
}
public int size() {
lock.lock(); // Happens before return size because...
// ...program order.
try {
return size;
} finally {
lock.unlock();
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.