Fre*_*ind 2 java multithreading locking synchronized
假设我有一个全局对象:
class Global {
public static int remoteNumber = 0;
}
Run Code Online (Sandbox Code Playgroud)
有一个线程定期运行以从远程获取新号码,并更新它(仅写入):
new Thread {
@override
public void run() {
while(true) {
int newNumber = getFromRemote();
Global.remoteNumber = newNumber;
Thread.sleep(1000);
}
}
}
Run Code Online (Sandbox Code Playgroud)
并且有一个或多个线程remoteNumber随机使用这个全局(只读):
int n = Global.remoteNumber;
doSomethingWith(n);
Run Code Online (Sandbox Code Playgroud)
你可以看到我没有使用任何锁或synchronize保护它,对吗?是否有任何可能导致问题的潜在问题?
更新:
就我而言,读取线程必须实时获取最新的新值并不重要。我的意思是,如果有任何问题(由于缺少锁/同步导致)使一个读取线程错过了该值,这并不重要,因为它很快就会有机会运行相同的代码(可能在循环中)
但是不允许读取未确定的值(我的意思是,如果旧值为 20,则新的更新值为 30,但读取线程读取的值不存在,例如 33,我不确定是否可能)
您需要在此处进行同步(有一个警告,我将在稍后讨论)。
主要问题是读取器线程可能永远不会看到写入器线程所做的任何更新。通常任何给定的写入最终都会被看到。但是在这里您的更新循环非常简单,以至于可以轻松地将写入保存在缓存中,而永远不会将其发送到主内存。所以你真的必须在这里同步。
编辑 11/2017我将更新这个并说一个值可以在缓存中保存这么长时间可能是不现实的。我认为这是一个问题,尽管像这样的变量访问可以由编译器优化并保存在寄存器中。因此仍然需要(或volatile)同步来告诉优化器确保为每个循环实际获取一个新值。
因此,您要么需要使用volatile,要么需要使用(静态)getter 和 setter 方法,并且您需要synchronized在这两种方法上使用关键字。对于偶尔这样写,volatile关键字的重量要轻得多。
需要注意的是,如果您确实不需要看到来自写入线程的及时更新,则不必进行同步。如果无限期延迟不会影响您的程序功能,您可以跳过同步。但是像这样的计时器看起来并不是省略同步的好用例。
编辑:根据Java Concurrency in Practice 中的Brian Goetz 的说法,Java/a JVM 不允许向您显示“不确定”值——从未写过的值。这些在技术上被称为“凭空而来”的值,Java 规范不允许使用这些值。您肯定会看到先前对全局变量进行的一些写入,无论是初始化时使用的零,还是一些后续写入,但不允许使用其他值。
| 归档时间: |
|
| 查看次数: |
2568 次 |
| 最近记录: |