Volatile使用常见误区
Volatile
使用最常见的误区就是并发 i++, i++是依赖当前 i 值,如果多个线程同时给当前值+1,可能同时返回,导致与预期值不符合。
比如两个线程同时读到 i 的当前值8,都进行加一,然后写回,最终 i 的结果是 9,而不是我们期待的10,丢失了更新。那么原子变量的引入就是针对volatile的这个缺陷的!!
原子变量的修改操作允许它依赖于当前值,所以说”原子变量“是比volatile的语义稍微强化一点!他不仅具有volatile的可见性,同时对原子变量的修改可以依赖于当前值。
原子变量的实现,使用了 volatile和unsafe方法, volatile保证可见性,unsafe保证原子性
代码测试
public class VolitaileTest {
private static volatile int i = 0;
private static AtomicInteger count = new AtomicInteger(0);
private static class Plus implements Runnable{
@Override
public void run() {
i++;
count.getAndIncrement();
}
}
public static void main(String[] args) {
for (int i1 = 0; i1 < 1000; i1++) {
Thread t = new Thread(new Plus());
t.start();
}
System.out.println(i);
System.out.println(count);
}
}
输出
999
1000
可以看到,在并发场景下,volatile++会出现不符合预期值的情况,但是 原子变量是没问题的。
实现三个线程有序输出
有三个线程,并发情况下,按顺序调用。
-
join() : 主线程看到 子线程的join() 方法,会停止等待子线程执行完
fir.start(); fir.join(); sec.start(); sec.join(); thr.start();
-
Executors.newSingleThreadExecutor()
创建单线程池,挨个执行ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.submit(fir); executorService.submit(sec); executorService.submit(thr); executorService.shutdown();