步驟 1 : 原子性操做概念html
所謂的原子性操做即不可中斷的操做,好比賦值操做java
int i = 5;
原子性操做自己是線程安全的 可是 i++ 這個行爲,事實上是有3個原子性操做組成的。安全
步驟 1. 取 i 的值 步驟 2. i + 1 步驟 3. 把新的值賦予i
這三個步驟,每一步都是一個原子操做,可是合在一塊兒,就不是原子操做。就不是線程安全的。 換句話說,一個線程在步驟1 取i 的值結束後,尚未來得及進行步驟2,另外一個線程也能夠取 i的值了。 這也是分析同步問題產生的緣由 中的原理。 i++ ,i--, i = i+1 這些都是非原子性操做。 只有int i = 1,這個賦值操做是原子性的。多線程
步驟 2 : AtomicInteger測試
JDK6 之後,新增長了一個包java.util.concurrent.atomic,裏面有各類原子類,好比AtomicInteger。 而AtomicInteger提供了各類自增,自減等方法,這些方法都是原子性的。 換句話說,自增方法 incrementAndGet 是線程安全的,同一個時間,只有一個線程能夠調用這個方法。atom
package multiplethread; import java.util.concurrent.atomic.AtomicInteger; public class TestThread { public static void main(String[] args) throws InterruptedException { AtomicInteger atomicI =new AtomicInteger(); int i = atomicI.decrementAndGet(); int j = atomicI.incrementAndGet(); int k = atomicI.addAndGet(3); } }
步驟 3 : 同步測試spa
分別使用基本變量的非原子性的**++運算符和 原子性的AtomicInteger對象的 incrementAndGet** 來進行多線程測試。 測試結果如圖所示線程
package multiplethread; import java.util.concurrent.atomic.AtomicInteger; public class TestThread { private static int value = 0; private static AtomicInteger atomicValue =new AtomicInteger(); public static void main(String[] args) { int number = 100000; Thread[] ts1 = new Thread[number]; for (int i = 0; i < number; i++) { Thread t =new Thread(){ public void run(){ value++; } }; t.start(); ts1[i] = t; } //等待這些線程所有結束 for (Thread t : ts1) { try { t.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.printf("%d個線程進行value++後,value的值變成:%d%n", number,value); Thread[] ts2 = new Thread[number]; for (int i = 0; i < number; i++) { Thread t =new Thread(){ public void run(){ atomicValue.incrementAndGet(); } }; t.start(); ts2[i] = t; } //等待這些線程所有結束 for (Thread t : ts2) { try { t.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.printf("%d個線程進行atomicValue.incrementAndGet();後,atomicValue的值變成:%d%n", number,atomicValue.intValue()); } }
更多內容,點擊瞭解: 多線程 原子訪問3d