如果只有一个线程写入而多个线程读取,是否需要添加一些锁或同步?
说我有一个全局对象:
class Global { public static int remoteNumber = 0;
}
有一个线程定期运行以从远程获取新编号并更新(仅写入):
new Thread { @override
public void run() {
while(true) {
int newNumber = getFromRemote();
Global.remoteNumber = newNumber;
Thread.sleep(1000);
}
}
}
并且有一个或多个线程remoteNumber
随机使用此全局变量(仅读取):
int n = Global.remoteNumber;doSomethingWith(n);
您可以看到我不使用任何锁或对其synchronize
进行保护,对吗?是否有可能引起问题的潜在问题?
更新:
就我而言,读取线程必须实时获取最新的值并不是很重要。我的意思是,如果有任何问题(由于缺少锁定/同步而导致)使一个读取线程错过了该值,那就没关系了,因为它将有机会尽快运行相同的代码(也许在循环中)
但是不允许读取未确定的值(我的意思是,如果旧值是20,新的更新值是30,但是读取线程读取的值不存在,例如33,我不确定是否可能)
回答:
您需要在这里进行同步(有一个警告,我将在后面讨论)。
主要问题是读取器线程可能永远看不到写入器线程进行的任何更新。通常,任何给定的写入最终都会被看到。但是在这里,您的更新循环非常简单,以至于写入可以轻松地保存在缓存中,而永远不会写入主内存。因此,您实际上必须在这里同步。
我将更新此内容,并说一个值可能在缓存中保留这么长时间可能是不现实的。我认为,这样的变量访问可以由编译器优化并保存在寄存器中,这是一个问题。因此,仍然需要同步(或volatile
)来告知优化器确保为每个循环实际获取一个新值。
因此,您要么需要使用volatile
,要么需要使用(静态)getter和setter方法,并且synchronized
在这两种方法上都需要使用关键字。对于偶尔这样的写法,volatile
关键字的权
轻 。
需要注意的是,如果您真的不需要查看来自写入线程的及时更新,则不必进行同步。如果无限期的延迟不会影响您的程序功能,则可以跳过同步。但是在计时器上这样的事情看起来并不适合用来省略同步。
编辑:Per Brian Goetz在 Java Java Concurrency in Practice中 ,不允许Java / a
JVM向您显示“不确定”值-从未写入的值。从技术上讲,这些值称为“凭空传播”的值,并且Java规范不允许使用它们。您可以确保看到先前对全局变量进行的写操作,它是初始化时使用的零,也可以是后续的写操作,但不允许其他值。
以上是 如果只有一个线程写入而多个线程读取,是否需要添加一些锁或同步? 的全部内容, 来源链接: utcz.com/qa/405232.html