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

tim*_*ann 8 java multithreading atomic atomicinteger

我在Oracle文档中读过:

  • 读取和写入对于引用变量和大多数 原始变量(除long和double之外的所有类型)都是原子的.

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

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

5go*_*der 17

虽然普通的单个存储或普通的单个加载int在Java中是原子的,但是你不能原子地增加它.这样做需要先加载值,然后根据它计算新值,然后再存储新值.但是在两次访问之间,另一个线程可能已经修改了该值.AtomicInteger提供这样的操作getAndIncrement可以用于此目的而无需使用锁.


Ted*_*opp 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
Run Code Online (Sandbox Code Playgroud)

(这两种意见的上面是假设下i,并j没有被讨论的发言时间改变开始执行,但可能被执行开始之后,但它完成之前另一个线程来改变.)


Bar*_*end 5

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

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

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

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

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

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

  • Java中的任何内容都不会"通过引用传递".您试图描述的想法是'AtomicInteger`是_reference type_."AtomicInteger"类型的每个参数都是对某个对象的引用,就像每个局部变量和该类型的每个字段一样.如果我有'AtomicInteger ai = someAtomicInteger;`并且我调用了一个pass-by-reference函数`foobar(ai)`,那么`foobar`函数就可以改变`ai`来引用一些_other_ AtomicInteger对象.这在Java中永远不会发生.Java总是按值调用.只是在Java中,"值"通常是引用. (2认同)