Java中Atomic set vs volatile set的区别?

时间:2016-06-09 04:44:47

标签: java multithreading concurrency

说我有以下两个班级。

public class Foo {
   private volatile Integer x = 0;
   private volatile boolean istrue = false;

   public void setInt(int x) {
       this.x = x;
   }

   public void setBoolean(boolean istrue) {
       this.istrue = istrue;
   }

   public Integer getInt() {
       return x;
   }
}

VS

public class Bar {
   private volatile AtomicInteger x = 0;
   private volatile AtomicBoolean istrue = false;

   public void setInt(int x) {
       this.x.set(x);
   }

   public void setBoolean(boolean istrue) {
       this.istrue.set(istrue);
   }

   public Integer getInt() {
       return this.x.get();
   }
}

假设多个线程可以访问Foo或Bar。这两个类是否安全?这两个班的真正区别是什么?

3 个答案:

答案 0 :(得分:1)

在当前示例中,您在方法中有单个赋值语句。我想你需要提出一个更好的例子。因为赋值将在单个指令中执行。这使得两个实现线程都安全。即使两个不同的线程有可能在访问它们时看到int的不同值,因为到时候,其他线程可能会重置(设置)为不同的值。

检查出来:What is thread Safe in java?

答案 1 :(得分:1)

这两个类都是编写的线程安全的。使用volatile变量和java.util.concurrent.atomic类之间的区别在于原子类允许以原子方式执行更复杂的操作,例如compare和set。只需直接访问volatile变量,就可以在比较和集合之间进行线程上下文切换,因此在完成集合时,您无法依赖比较结果仍然有效。

答案 2 :(得分:1)

这两个类都是线程安全的。但这不是你的问题。

Foo :对字段的读取和写入都是原子的。但更复杂的操作,如i ++则不然。 i ++转换为i = i + 1,它分解为读取和写入,因此可以在两者之间切换线程上下文,使整个操作不是原子操作。

Bar :volatile使原子字段本身的访问成为原子,因此您可以使用原子方式使用新引用重新分配字段。然而,compareAndSetinc等字段上的操作是原子的。问题是,您是否需要对字段进行原子写入访问或仅需要操作的原子性?由于AtomicXXX类型只是值的容器,因此通常不会重新分配变量,而是重新分配原子的值。

所以这应该足够了:

private final AtomicInteger x = new AtomicInteger(0);
private final AtomicBoolean istrue = new AtomicBoolean(false);