如果对int变量的写入和读取是原子的,为什么需要AtomicInteger?

时间:2017-02-05 16:34:04

标签: java multithreading atomic atomicinteger

我在Oracle docs读到:

  
      
  • 对于参考变量和大多数来说,读取和写入都是原子   原始变量(除long和double之外的所有类型)。
  •   

(我想这个功能已经在一些新的JDK版本中添加了,因为我曾经认为所有原始变量的读/写都不是原子的)

这是否意味着message Alarm { uint32 hour = 1; uint32 minute = 2; bool repeat = 3; DaysOfWeek daysOfWeek = 4; message DaysOfWeek { bool sunday = 1; bool monday = 2; bool tuesday = 3; bool wednesday = 4; bool thursday = 5; bool friday = 6; bool saturday = 7; } } 已被弃用且不应在新项目中使用?

4 个答案:

答案 0 :(得分:16)

虽然来自普通#selector单个存储单个加载在Java中是原子的,但您不能原子地(例如)递增它。这样做需要先加载值,然后根据它计算新值,然后再存储新值。但是在两次访问之间,另一个线程可能已经修改了该值。 int提供getAndIncrement之类的操作,无需使用锁即可用于此目的。

答案 1 :(得分:7)

弃用?一点也不。虽然原始变量的单独读取和写入是原子的,但AtomicInteger(以及java.util.concurrent.atomic中的其他原子类)提供了更复杂的操作,这些操作也是原子的。这些包括addAndGet(int)之类的东西,它们对原始int变量完全不是原子的。因此,

int i = 3;
AtomicInteger j = new AtomicInteger(3);
i += 5; // NOT thread-safe -- might not set i to 8
int n = j.addAndGet(5); // thread-safe -- always sets n to 8

(上述两条评论均假设ij在问题开始执行时没有更改,但可能会被更改执行开始后但在完成之前的另一个线程。)

答案 2 :(得分:5)

  

是否意味着AtomicInteger已被弃用且不应在新项目中使用?

没有。首先也是最明显的,如果它被弃用,它将被标记为这样。

此外,AtomicInteger和原始int根本不可互换。有很多不同之处,但这里有前三个想到的:

  • AtomicInteger可以通过引用传递,不像raw int,它是通过值传递的。
  • AtomicInteger有一些在基元上不可用的操作,例如compareAndSet()
  • 即使表面上看起来相同的那些,即AtomicInteger.getAndIncrement()int++也不同;前者是原子的,第二种是两种非原子的操作。
  

我想这个功能已经在一些新的JDK版本中添加了,因为我曾经认为所有原始变量的读/写都不是原子的

读取和写入32位或更小的基元始终是原子的。

答案 3 :(得分:3)

其他答案解决了为什么需要AtomicInteger。我想澄清一下该文件的内容。

在该文档中使用术语 atomic AtomicInteger中使用 atomic 的目的不同。

该文件还说明了

  

原子动作不能交错,因此可以毫无顾虑地使用它们   线程干扰。

这是指

int x;
x = 1; // thread 1
x = 2; // thread 2
System.out.println(x); // thread 3

thread 3保证会看到值1或值2

但是,对于longdouble,您没有这种保证。 Java Language Specification

  

出于Java编程语言内存模型的目的,a   单个写入非易失性longdouble值被视为两个   单独写入:每个32位一半。这可能导致a   线程看到64位值的前32位的情况   一次写入,另一次写入的第二次32位。

所以,例如,

long x;
x = 0xffff_ffffL; // thread 1
x = 0x7fff_ffff_0000_0000L; // thread 2
System.out.println(x); // thread 3
允许

thread 3查看thread 1分配的前32位和thread 2分配的最后32位,创建long 1}}值7fff_ffff_ffff_ffffdouble也可能出现同样的情况。

使用long修改doublevolatile变量会阻止此行为。