如果只有一个线程写入而多个线程读取,是否需要添加一些锁或同步?

说我有一个全局对象:

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

回到顶部