![](/img/trans.png)
[英]Signal running thread1 to complete method1 after thread2 enters method2
[英]Do we need to make a field 'volatile', if Thread1 enters sync block, updates it, is still inside the sync block, Thread2 outside of sync reads field?
假设我们有一个“A 类”,它有一个数据成员“var”。
class A
{
int var;
method()
{
read(var);
synchronized block
{
update var here;
}
}
假设线程 1 获得锁并进入同步块。 它更新字段值“var”。 假设字段值由线程缓存在处理器的核心中。 它更新缓存中的值。
现在线程 2 开始运行,进入 method(),并读取字段值 'var'。
线程 2,肯定会得到更新的值吗? 是否同步确保线程 2 将获得更新的值,即使线程 1 尚未退出同步。 在这种情况下,我们是否需要使 'var' 易变?
PS - 一切都发生在同一个对象上。
是否同步确保线程 2 将获得更新的值
不,如果线程没有进入synchronized
块, synchronized
不会为线程做任何事情。 考虑synchronized
的方法是这样的:无论一个线程在离开同步块之前做什么,都保证在第二个线程随后*进入在同一个锁对象上synchronized
的块时对其他线程可见。
对于单个int
变量,您可以改为将其volatile
。 volatile
提供类似于synchronized
的保证:无论一个线程在更新volatile
变量之前做什么,都保证在第二个线程随后*读取相同的volatile
变量时对其他线程可见。
* 编辑:我添加了“随后”以明确表示synchronized
和volatile
都不足以确保线程将以某种特定顺序访问var
。 如果您希望确保线程 2在线程 1 分配它之前不会尝试读取var
,那么您将不得不使用其他一些方法†来协调它们的活动。 正确使用synchronized
或volatile
只能确保IF线程 1 在线程 2 检查之前更新var
,然后线程 2 会看到更新。
† 有很多“其他方式”。 一个例子是Semaphore
。 线程 1 可以在更新var
后release()
信号量的许可,线程 2 可以在读取var
之前acquire()
许可。 如果在线程 1 完成其工作之前到达信号量, acquire()
调用将导致线程 2 等待。
如果你不让 'var' 易失,那么在写入和读取 'var' 之间就没有发生之前的边缘。 所以你手上有一个数据竞赛,奇怪的事情可能会发生,比如编译器把事情搞砸了。
简而言之:使其易失(或确保您使用相同的锁读取“var”)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.