Java 中的 AtomicInteger
今天我们将研究AtomicInteger
Java。原子操作在单个任务单元中执行,不受其他操作的干扰。原子操作在多线程环境中是必需的,可以避免数据不一致。
原子整数
让我们创建一个简单的多线程程序,其中每个线程都会将共享count
变量增加 4 次。因此,如果有两个线程,则它们完成后count
值应该是 8。JavaAtomic.java
package com.journaldev.concurrency;
public class JavaAtomic {
public static void main(String[] args) throws InterruptedException {
ProcessingThread pt = new ProcessingThread();
Thread t1 = new Thread(pt, "t1");
t1.start();
Thread t2 = new Thread(pt, "t2");
t2.start();
t1.join();
t2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ProcessingThread implements Runnable {
private int count;
@Override
public void run() {
for (int i = 1; i < 5; i++) {
processSomething(i);
count++;
}
}
public int getCount() {
return this.count;
}
private void processSomething(int i) {
// processing some job
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
如果您运行上述程序,您会注意到count
值在 5、6、7、8 之间变化。原因是count++不是原子操作。因此,当一个线程读取它的值并将其加一时,另一个线程已经读取了较旧的值,从而导致错误的结果。为了解决这个问题,我们必须确保 count 上的增量操作是原子的,我们可以使用同步来做到这一点,但 Java 5java.util.concurrent.atomic
为 int 和 long 提供了包装类,可用于实现此原子操作而无需使用同步。
Java AtomicInteger 示例
这是更新后的程序,它将始终输出计数值为 8,因为AtomicInteger
方法incrementAndGet()
原子地将当前值加一。
package com.journaldev.concurrency;
import java.util.concurrent.atomic.AtomicInteger;
public class JavaAtomic {
public static void main(String[] args) throws InterruptedException {
ProcessingThread pt = new ProcessingThread();
Thread t1 = new Thread(pt, "t1");
t1.start();
Thread t2 = new Thread(pt, "t2");
t2.start();
t1.join();
t2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ProcessingThread implements Runnable {
private AtomicInteger count = new AtomicInteger();
@Override
public void run() {
for (int i = 1; i < 5; i++) {
processSomething(i);
count.incrementAndGet();
}
}
public int getCount() {
return this.count.get();
}
private void processSomething(int i) {
// processing some job
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
使用并发类进行原子操作的好处是我们不需要担心同步。这提高了代码的可读性,并减少了出错的可能性。此外,原子操作并发类被认为比涉及锁定资源的同步更有效。