通过 ThreadPoolExecutor.execute() 保证内存可见性
如果您使用 ThreadPoolExecutor 执行 Runnable,并且此 Runnable 修改了某些共享状态,是否可以保证这些对共享状态的更改在提交可运行对象的原始线程中是否可见游泳池?假设只有 1 个共享状态的写入者和 1 个读取者。我知道,当您使用返回 Future
的 ExecutorService
时,执行 Future.get()
将保证可见性。
class State {
private int x;
public State(int y) { x = y; }
public void setX(int y) { x = y; }
public int getX() { return x; }
}
main() {
threadPool = new ThreadPoolExecutor(8, 16, 100, TimeUnit.SECONDS, new ArrayBlockingQueue(...))
final State myState = new State(1);
threadPool.execute(new Runnable() {
public void run() {
myState.setX(50);
}
});
while (true) {
if (myState.getX() == 50) {
break;
}
sleep();
} // would this loop terminate?
}
If you execute a Runnable with a ThreadPoolExecutor
, and if this Runnable modifies some shared state, is there any guarantee as to whether these changes to the shared state will be visible in the original thread that submitted the runnable to the pool? Assume there's only 1 writer to shared state and 1 reader. I know that when you use the ExecutorService
which returns a Future
, doing a Future.get()
will guarantee visibility.
class State {
private int x;
public State(int y) { x = y; }
public void setX(int y) { x = y; }
public int getX() { return x; }
}
main() {
threadPool = new ThreadPoolExecutor(8, 16, 100, TimeUnit.SECONDS, new ArrayBlockingQueue(...))
final State myState = new State(1);
threadPool.execute(new Runnable() {
public void run() {
myState.setX(50);
}
});
while (true) {
if (myState.getX() == 50) {
break;
}
sleep();
} // would this loop terminate?
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这取决于情况,没有隐式保证状态更改将立即反映在原始线程中,主要是因为原始线程可能有一个
x
值的缓存副本,该副本在以下情况下不会更新:另一个线程更改主内存中x
的值。您可以通过使用
volatile
关键字添加显式保证来解决此问题,例如:这告诉编译器它无法缓存
x
的值,并且每次程序读取x
它必须检查主内存中的值。这将导致原始线程在任何其他线程修改它时立即看到x
的新值。更多详细信息请参见:
http://www.javamex.com/tutorials/synchronization_volatile.shtml
It depends, there is no implicit guarantee that the change in state will be immediately reflected in the original thread, primarily because the original thread may have a cached copy of the value of
x
that will not be updated when another thread changes the value ofx
in main memory.You can work around this by adding an explicit guarantee using the
volatile
keyword, like:This tells the compiler that it cannot cache the value of
x
, and that every time the program readsx
it must check the value that is in main memory. This will cause the original thread to see the new value ofx
as soon as any other thread modifies it.More details here:
http://www.javamex.com/tutorials/synchronization_volatile.shtml
几乎任何检测线程已完成其工作的明智方法(除了仅同步该一个变量的 volatile 之外)也将保证内存的同步视图。您的示例无法确保线程已完成,因此它显然不起作用。 C# 不提供任何特定的及时性保证,因此您不能使用
sleep
作为同步形式。Pretty much any sane way to detect that the thread has finished its work (other than
volatile
which only synchronizes that one variable) will also guarantee a synchronized view of memory. Your example has no way to be sure the thread has finished, so it obviously won't work. C# doesn't provide any particular timeliness guarantees, so you can't usesleep
as a form of sychronization.