多線程並發之原子性(六)
阿新 • • 發佈:2017-05-24
解決 tile start 基本上 barrier stack import 說明 ken
原子是世界上的最小單位,具有不可分割性。比如 a=0;(a非long和double類型) 這個操作是不可分割的,那麽我們說這個操作時原子操作。再比如:a++; 這個操作實際是a = a + 1;是可分割的,所以他不是一個原子操作。非原子操作都會存在線程安全問題,需要我們使用同步技術(sychronized)來讓它變成一個原子操作。一個操作是原子操作,那麽我們稱它具有原子性。Java的concurrent包下提供了一些原子類,我們可以通過閱讀API來了解這些原子類的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。
因為原子性是線程安全的,所以關於原子性自增是不需要傳統的加鎖技術的,具體看代碼:
運行結果也是:10000
最近在網上找到好多的多線程關於原子性的例子,說的都不是非常的明確,對於剛學習多線程的新手而言很容誤導學員,在這裏,我通過多個例子對多線程的原子性加以說明。
例子一:傳統技術自增
package face.thread.volatilep; public class Counter2 { private int count = 0; public synchronized void inc() { count = count + 1; } public static void main(String[] args) { //同時啟動1000個線程,去進行i++計算,看看實際結果 final Counter2 c = new Counter2(); for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { @Override public void run() { c.inc(); } }).start(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //這裏每次運行的值都有可能不同,可能為1000 System.out.println("運行結果:Counter.count=" + c.count); } }
以上代碼打印的結果偶爾會等於1000,基本上都會有一些誤差,原因是線程執行的順序無法保證的,很可能在新建的1000個線程還沒有執行完,我們的代碼
System.out.println("運行結果:Counter.count=" + Counter.count);
就已經執行完了,要想解決這個問題很簡單,那就是在最後一句println之前在線程睡眠一段時間,比如睡眠2秒鐘。等1000個線程執行完了,在打印"
"運行結果:Counter.count=" + Counter.count";
還可以借助於線程輔助類解決,在這裏就舉例一個最簡單的例子展示:
package face.thread.volatilep; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class Counter3 { int count =0; public synchronized void inc() { count++; } public static void main(String[] args) { //同時啟動1000個線程,去進行i++計算,看看實際結果 final Counter3 c = new Counter3(); final CyclicBarrier cy = new CyclicBarrier(10000, new Runnable() { public void run() { //這裏每次運行的值都有可能不同,可能為1000 System.out.println("運行結果:Counter.count=" + c.count); } }); for (int i = 0; i < 10000; i++) { new Thread(new Runnable() { @Override public void run() { c.inc(); try { cy.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }).start(); } } }
例子二:原子性自增
原子是世界上的最小單位,具有不可分割性。比如 a=0;(a非long和double類型) 這個操作是不可分割的,那麽我們說這個操作時原子操作。再比如:a++; 這個操作實際是a = a + 1;是可分割的,所以他不是一個原子操作。非原子操作都會存在線程安全問題,需要我們使用同步技術(sychronized)來讓它變成一個原子操作。一個操作是原子操作,那麽我們稱它具有原子性。Java的concurrent包下提供了一些原子類,我們可以通過閱讀API來了解這些原子類的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。
因為原子性是線程安全的,所以關於原子性自增是不需要傳統的加鎖技術的,具體看代碼:
package face.thread.volatilep; import java.util.concurrent.atomic.AtomicInteger; public class CounterNew2{ AtomicInteger count = new AtomicInteger(0); public void increment() { count.getAndIncrement(); } public int getCount() { return count.get(); } public static void main(String[] args) { final CounterNew2 cn = new CounterNew2(); for(int i = 0 ; i < 10000;i++){ new Thread(new Runnable() { public void run() { cn.increment(); } }).start(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("count最終返回值:" + cn.getCount()); } }
多線程並發之原子性(六)