2

我有一个带有单个原子操作的方法,比如这个

int value;

public void setValue(int value) {
    this.value = value;
}

然后我以明显的方式称呼它,例如

foo.setValue(10);

问题是:它会是原子操作吗?如果否,将执行哪些原子操作?我如何在我的电脑上测试这个(如果可以的话)?

4

3 回答 3

11

是的

this.value = value;

操作是原子的。请参阅Java 语言规范:线程和锁

请注意,尽管允许线程缓存它们自己的非易失性变量值,因此不能保证连续的get操作会产生最后一个设置

要摆脱这类数据竞争,您需要以某种方式同步对变量的访问。这可以通过

  • 使方法同步,
  • 通过让变量是易变的,或者,
  • AtomicIntegerjava.util.concurrent包装中使用。(首选方式imo)

还应注意,如果您从 更改为或,该操作将不是原子的。以下是 JLS 的相关部分:intlongdouble

17.4 double 和 long 的非原子处理

如果 double 或 long 变量未声明为 volatile,则出于加载、存储、读取和写入操作的目的,它们被视为每个 32 位的两个变量:只要规则需要这些操作之一,两个这样的操作执行操作,每个 32 位一半执行一个操作。


一些有用的链接:

于 2011-02-07T19:24:35.460 回答
1

它是原子的,因为它只是一个原始的 32 位值。

因此,当您阅读它时,可以保证您会看到由其中一个线程设置的值,但您不知道它是哪一个。

如果它是 a long,您将不会有相同的保证,尽管实际上大多数 VM 实现确实将long写入视为原子操作。

这是JLS在这个问题上必须说的:

鼓励 VM 实现者尽可能避免拆分其 64 位值。鼓励程序员将共享的 64 位值声明为 volatile 或正确同步他们的程序以避免可能的并发症。

但是使用 ints 你是安全的,问题是,这个非常弱的保证对你来说足够了吗?通常情况下,答案是否定的。

于 2011-02-07T19:27:09.540 回答
1

首先,根据 Java 规范,对 Java 中所有原始类型(64 位除外)的赋值是原子的。但是例如自动增量不是线程安全的,无论您使用哪种类型。

但是这段代码的真正问题不是原子性,而是可见性。如果两个线程正在修改value,它们可能看不到彼此所做的更改。使用volatile关键字,甚至更好,AtomicInteger以保证正确的同步可见性。

请注意,synchronized关键字还保证可见性,这意味着如果在synchronnized块内部发生某些修改,则保证它将被其他线程可见。

于 2011-02-07T19:27:53.583 回答