Java 方法调用和原子性

Java 方法调用和原子性,java,concurrency,atomic,method-call,Java,Concurrency,Atomic,Method Call,我有一个单原子操作的方法,就像这个 int value; public void setValue(int value) { this.value = value; } 然后我用一种明显的方式来称呼它,比如 foo.setValue(10); 问题是:这会是原子操作吗?如果否,将执行哪些原子操作?如何在我的电脑上测试(如果可以的话)?是的 this.value = value; 操作是原子的。看 请注意,尽管允许线程缓存它们自己的非易失性变量值,但不能保证连续的get操作会产生最

我有一个单原子操作的方法,就像这个

int value;

public void setValue(int value) {
    this.value = value;
}
然后我用一种明显的方式来称呼它,比如

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

是的

this.value = value;
操作是原子的。看

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

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

  • 使方法同步
  • 通过让变量不稳定或
  • java.util.concurrent
    包中使用。(国际海事组织首选方式)

还应注意,如果将
int
更改为
long
double
,则操作不会是原子操作。以下是JLS的相关章节:

17.4双波长和长波长的非原子处理

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


一些有用的链接:


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

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

      如果它是一个
      long
      ,您就不会有相同的保证,尽管在实践中,大多数VM实现都将
      long
      写操作视为原子操作

      以下是联合联络小组在这个问题上的发言:

      鼓励VM实现者尽可能避免拆分其64位值。鼓励程序员将共享的64位值声明为易失性,或正确同步其程序,以避免可能的复杂性


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

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

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


      请注意,
      synchronized
      关键字还可以保证可见性,这意味着如果在
      synchronized
      块中发生某些修改,则可以保证其他线程可以看到它。

      谢谢。回答得好。我有一个相对的问题:在哪些情况下,同步方法比volatite变量更可取?(我是否应该为这一主题创建新的主题?)我个人的建议是尽可能保持所有内容的高水平。也就是说,1)使用java.util.concurrent类,2)使用
      synchronized
      ,3)使用
      volatile
      变量。