众所周知,++操做并非线程安全的。这篇文章主要讲述其非线程安全的缘由以及相关问题。java
i++
分为如下3步:安全
这3步每一步之间都是能够被中断的,加volatile只是保证从内存中读取到的count值是最新的值,可是存在在别的线程中的count还未写回主存的可能。ide
例如:性能
public class ThreadTest implements Runnable { int count = 0; @Override public void run() { synchronized (this) { for (int i = 0; i < 100000; i++) { count++; } } } public static void main(String[] args) throws ExecutionException, InterruptedException { Runnable runnable = new ThreadTest(); ExecutorService executorService = Executors.newFixedThreadPool(3); Future f1, f2; f1 = executorService.submit(runnable); f2 = executorService.submit(runnable); f1.get(); f2.get(); System.out.println(((ThreadTest) runnable).count); executorService.shutdown(); } }
原子类能够的单一操做都是原子性的。它的实现并非依赖于加锁而是使用CAS。this
CAS的基本原理以下:atom
从内存位置V中读取值A,并根据A计算值B,而后再将值B写回V。
可是写回V以前,会检查内存位置V的值是否等于A,若是不等于,就不会将值写回V。而是从新进行一次上述操做。线程
public class ThreadTest2 implements Runnable { AtomicInteger count = new AtomicInteger(); @Override public void run() { synchronized (this) { for (int i = 0; i < 100000; i++) { count.getAndIncrement(); } } } public static void main(String[] args) throws ExecutionException, InterruptedException { Runnable runnable = new ThreadTest2(); ExecutorService executorService = Executors.newFixedThreadPool(3); Future f1, f2; f1 = executorService.submit(runnable); f2 = executorService.submit(runnable); f1.get(); f2.get(); System.out.println(((ThreadTest2) runnable).count.get()); executorService.shutdown(); } }
加锁固然会必定程度上影响性能,可是正确性优于性能。code
使用java.util.concurrent.atomic
中的原子类在不少状况下都有着优于锁的性能,可是在本例中并非如此。我认为是由于compare比较错误次数太多,重复次数太多致使的。内存