我理解AtomicInteger和其他原子变量允许并发访问。在什么情况下通常使用这个类?


当前回答

关键是它们允许安全的并发访问和修改。它们通常在多线程环境中用作计数器——在引入它们之前,这必须是一个用户编写的类,将各种方法包装在同步块中。

其他回答

如果您查看AtomicInteger具有的方法,您将注意到它们倾向于对应于对int的常见操作。例如:

static AtomicInteger i;

// Later, in a thread
int current = i.incrementAndGet();

是线程安全的版本:

static int i;

// Later, in a thread
int current = ++i;

方法映射如下: ++i是i. incrementandget () i++就是i. getandincrement () ——i是i. decrementandget () i——是i. getanddecrement () I = x = I .set(x) X = I = X = I .get()

还有其他方便的方法,如compareAndSet或addAndGet

AtomicInteger有两个主要用途:

As an atomic counter (incrementAndGet(), etc) that can be used by many threads concurrently As a primitive that supports compare-and-swap instruction (compareAndSet()) to implement non-blocking algorithms. Here is an example of non-blocking random number generator from Brian Göetz's Java Concurrency In Practice: public class AtomicPseudoRandom extends PseudoRandom { private AtomicInteger seed; AtomicPseudoRandom(int seed) { this.seed = new AtomicInteger(seed); } public int nextInt(int n) { while (true) { int s = seed.get(); int nextSeed = calculateNext(s); if (seed.compareAndSet(s, nextSeed)) { int remainder = s % n; return remainder > 0 ? remainder : remainder + n; } } } ... } As you can see, it basically works almost the same way as incrementAndGet(), but performs arbitrary calculation (calculateNext()) instead of increment (and processes the result before return).

Atomic classes are not general purpose replacements for java.lang.Integer and related classes. They do not define methods such as equals, hashCode and compareTo. (Because atomic variables are expected to be mutated, they are poor choices for hash table keys.) Additionally, classes are provided only for those types that are commonly useful in intended applications. For example, there is no atomic class for representing byte. In those infrequent cases where you would like to do so, you can use an AtomicInteger to hold byte values, and cast appropriately. You can also hold floats using Float.floatToRawIntBits(float) and Float.intBitsToFloat(int) conversions, and doubles using Double.doubleToRawLongBits(double) and Double.longBitsToDouble(long) conversions.

参考:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html

例如,我有一个生成某些类实例的库。每个实例必须有一个唯一的整数ID,因为这些实例表示发送到服务器的命令,并且每个命令必须有一个唯一的ID。由于允许多个线程并发发送命令,所以我使用AtomicInteger来生成这些id。另一种方法是使用某种锁和常规整数,但这既慢又不优雅。

AtomicInteger的主要用途是在多线程上下文中,并且需要在不使用synchronized的情况下对整数执行线程安全操作。基本类型int上的赋值和检索已经是原子的,但AtomicInteger附带的许多操作在int上不是原子的。

最简单的是getAndXXX或xXXAndGet。例如,getAndIncrement()是i++的原子等价物,它不是原子的,因为它实际上是三个操作的捷径:检索、加法和赋值。compareAndSet对于实现信号量、锁、锁存器等非常有用。

使用AtomicInteger比使用同步执行相同的操作更快,可读性更强。

一个简单的测试:

public synchronized int incrementNotAtomic() {
    return notAtomic++;
}

public void performTestNotAtomic() {
    final long start = System.currentTimeMillis();
    for (int i = 0 ; i < NUM ; i++) {
        incrementNotAtomic();
    }
    System.out.println("Not atomic: "+(System.currentTimeMillis() - start));
}

public void performTestAtomic() {
    final long start = System.currentTimeMillis();
    for (int i = 0 ; i < NUM ; i++) {
        atomic.getAndIncrement();
    }
    System.out.println("Atomic: "+(System.currentTimeMillis() - start));
}

在我使用Java 1.6的PC上,原子测试在3秒内运行,而同步测试在5.5秒内运行。这里的问题是同步操作(notatomic++)非常短。所以同步的成本相对于操作来说是非常重要的。

除了原子性,AtomicInteger还可以作为一个可变版本的Integer,例如在map中作为值使用。