一、原子操作的概念
原子操作就是最小的,不可再次拆分的操作,也就是即不可中断的操作,比如赋值操作int i = 5;
比如 i++ 这个行为,事实上是有3个原子性操作组成的。
步骤 1. 取 i 的值
步骤 2. i + 1
步骤 3. 把新的值赋予i
这三个步骤,每一步都是一个原子操作,但是合在一起,就不是原子操作。就不是线程安全的。
换句话说,一个线程在步骤1 取i 的值结束后,还没有来得及进行步骤2,另一个线程也可以取 i的值了。
这也是分析同步问题产生的原因 中的原理。
i++ ,i–, i = i+1 这些都是非原子性操作。
只有int i = 1,这个赋值操作是原子性的。
二、AtomicInteger
JDK6 以后,新增加了一个包java.util.concurrent.atomic,里面有各种原子类,比如AtomicInteger。
而AtomicInteger提供了各种自增,自减等方法,这些方法都是原子性的。 换句话说,自增方法 incrementAndGet 是线程安全的,同一个时间,只有一个线程可以调用这个方法。
示例
public static void main(String[] args) throws InterruptedException {
AtomicInteger atomicI =new AtomicInteger();
System.out.println(atomicI.get());
int a = atomicI.decrementAndGet();
int b = atomicI.incrementAndGet();
int c = atomicI.addAndGet(3);
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
结果
0
-1
0
3
三、验证AtomicInteger是否为线程安全
测试用例
private static int num = 0;
private static AtomicInteger atomicI =new AtomicInteger();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
num += 1;
atomicI.incrementAndGet();
}
}
};
Thread thread2 = new Thread() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
num += 1;
atomicI.incrementAndGet();
}
}
};
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(num);
System.out.println(atomicI.get());
}
结果
1763
2000
可发现num 为1763,
atomicI为正确的2000。
可见atomicI是线程安全