衆所周知,++操做並非線程安全的。這篇文章主要講述其非線程安全的緣由以及相關問題。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比較錯誤次數太多,重複次數太多致使的。內存