gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 07:00:20 29 4
gpt4 key购买 nike

假设我有一个全局对象:

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,我不确定是否可能)

最佳答案

此处需要同步(有一个注意事项,我将在稍后讨论)。

主要问题是读取线程可能永远看不到写入线程所做的任何更新。通常任何给定的写入最终都会被看到。但是这里你的更新循环非常简单,写入可以很容易地保存在缓存中,永远不会进入主内存。所以你真的必须在这里同步。

EDIT 11/2017 我将对此进行更新,并指出将一个值在缓存中保存这么长时间可能是不现实的。我认为这是一个问题,尽管编译器可以优化这样的变量访问并将其保存在寄存器中。因此仍然需要同步(或 volatile)来告诉优化器确保为每个循环实际获取一个新值。

因此您要么需要使用volatile,要么需要使用(静态)getter 和setter 方法,并且您需要在这两种方法上使用synchronized 关键字.对于像这样的偶尔写入,volatile 关键字的重量较轻。

需要注意的是,如果您真的不需要从写线程看到及时的更新,则不必进行同步。如果无限期延迟不会影响您的程序功能,您可以跳过同步。但是在计时器上这样的事情看起来不像是省略同步的好用例。

编辑:根据 Brian Goetz 在 Java 并发实践 中的说法,Java/JVM 不允许向您显示“不确定”值——从未写入的值。这些在技术上更称为“凭空”值,Java 规范不允许使用它们。您一定会看到之前对您的全局变量所做的一些写入,无论是初始化它的零,还是一些后续写入,但不允许使用其他值。

关于java - 如果只有一个线程写入,多个线程读取,是否需要加一些锁或同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27120914/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com