【问题标题】:What is atomic?什么是原子的?
【发布时间】:2011-11-10 07:34:20
【问题描述】:

这是两个原子操作:

int value = 5;
Object obj = new Object();

但是当使用原语作为方法参数时,这是否会被视为原子操作: public void setValue(int val, Object obj){
this.value = val; // Atomic?
this.obj = obj; // Not atomic?
}

? 对象引用的副本不是原子的,因为它包括读取和写入,对吧?

是否正确地说,对对象引用进行原子操作的唯一方法是将其声明为 null 或为其分配一个新对象,例如:

Object obj = null;

Object obj = new Object();

?

【问题讨论】:

    标签: java terminology atomic


    【解决方案1】:

    如果上述方法中的参数是一个对象的引用, 那么操作不会是原子的,对吧?

    一般来说这是正确的。一个好的经验法则是考虑根本没有原子性,即使使用以下原语:

    int b,c; 
    int a = ++b - c;
    

    只有原语,但整个分配是潜在的而不是原子的。

    如果您需要确保原子操作,您有不同的可能性:

    • 同步块
    • 不可变对象
    • 特定库 (java.util.concurrent.atomic)

    【讨论】:

    • 感谢您的回答!我还编辑了我的问题,因此它现在包含在方法调用中使用对象引用时的代码示例。
    【解决方案2】:

    当一个线程读取一个原始值(long 和 double 除外)或一个对象引用的值时,它会看到它在此变量中设置的值,或另一个线程在此变量中设置的值。

    然而,虽然在一个线程中为共享变量赋值是原子的,但这并不意味着所有其他线程都会立即看到新值。为此,应将变量声明为 volatile。 volatile 还会对 long 和 double atomic 进行写入。不过,在这种情况下,我更喜欢使用 AtomicXxx(AtomicLong、AtomicBoolean 等)。

    如果您想以原子方式更改两个共享变量的值,那么您应该使用唯一锁同步对这些变量的每次访问(读取和写入)。

    此外,每个“检查然后行动”或“读取然后写入”操作都是非原子的。这意味着这些操作也需要同步:

    a++; // read a, increment value, write value to a
    if (a > 0) {a = b;} // check value of a, then assign new value to a.
    

    您问题中的每一个操作都是原子的。但是在setValue() 中,您有两个原子操作。整个setValue 调用不是原子的。

    【讨论】:

    • 感谢您提及“发生在之前”的关系。
    【解决方案3】:

    To the JLS!

    当一个线程使用一个变量的值时,它获得的值实际上是一个由该线程或其他线程存储到变量中的值。即使程序不包含正确同步的代码也是如此。例如,如果两个线程将对不同对象的引用存储到同一个引用值中,则该变量随后将包含对一个对象或另一个对象的引用,而不是对某个其他对象的引用或损坏的引用值。

    所以分配是原子的。

    【讨论】:

      【解决方案4】:
      public synchronized void setValue(int val, Object obj)
      

      现在整个函数都是“原子的”,我在 Java 中没有见过这个术语

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多