原子操作和同步:
原子执行在单个任务单元中执行,不会受到其他执行的影响。多线程环境下需要原子操作,避免数据不规则。
如果我们正在读/写一个 int 值,那么它就是一个原子操作。但通常如果它在一个方法内,那么如果该方法不同步,许多线程可以访问它,这可能导致值不一致。但是,int++ 不是原子操作。因此,当一个线程读取它的值并将其加一时,另一个线程已经读取了导致错误结果的旧值。
为了解决数据不一致,我们必须确保对 count 的递增操作是原子的,我们可以使用同步来做到这一点,但 Java 5java.util.concurrent.atomic
为 int 和 long 提供了包装类,可用于在不使用同步的情况下以原子方式实现这一点。
使用 int 可能会造成数据数据不一致,如下所示:
public class AtomicClass {
public static void main(String[] args) throws InterruptedException {
ThreardProcesing pt = new ThreardProcesing();
Thread thread_1 = new Thread(pt, "thread_1");
thread_1.start();
Thread thread_2 = new Thread(pt, "thread_2");
thread_2.start();
thread_1.join();
thread_2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ThreardProcesing 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();
}
}
}
输出:计数值在 5,6,7,8 之间变化
我们可以使用java.util.concurrent.atomic
始终将计数值输出为 8 来解决此问题,因为该AtomicInteger
方法incrementAndGet()
以原子方式将当前值加一。如下图:
public class AtomicClass {
public static void main(String[] args) throws InterruptedException {
ThreardProcesing pt = new ThreardProcesing();
Thread thread_1 = new Thread(pt, "thread_1");
thread_1.start();
Thread thread_2 = new Thread(pt, "thread_2");
thread_2.start();
thread_1.join();
thread_2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ThreardProcesing 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();
}
}
}
资料来源:java中的原子操作