Java线程详解(17)-原子量
生活随笔
收集整理的這篇文章主要介紹了
Java线程详解(17)-原子量
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
所謂的原子量即操作變量的操作是“原子的”,該操作不可再分,因此是線程安全的。
????????為何要使用原子變量呢,原因是多個線程對單個變量操作也會引起一些問題。在Java5之前,可以通過volatile、synchronized關鍵字來解決并發訪問的安全問題,但這樣太麻煩。
????????Java5之后,專門提供了用來進行單變量多線程并發安全訪問的工具包java.util.concurrent.atomic,其中的類也很簡單。
????????下面給出一個反面例子(切勿模仿):
import?java.util.concurrent.ExecutorService;?? import?java.util.concurrent.Executors;?? import?java.util.concurrent.atomic.AtomicLong;??/**?*?Java線程:新特征-原子量?*/?? public?class?Test?{??public?static?void?main(String[]?args){??//創建一個線程池??ExecutorService?pool?=?Executors.newFixedThreadPool(2);??Runnable?t1?=?new?MyRunnable("張三",?2000);??Runnable?t2?=?new?MyRunnable("李四",?3600);??Runnable?t3?=?new?MyRunnable("王五",?2700);??Runnable?t4?=?new?MyRunnable("老張",?600);??Runnable?t5?=?new?MyRunnable("老牛",?1300);??Runnable?t6?=?new?MyRunnable("胖子",?800);??//執行各個線程??pool.execute(t1);??pool.execute(t2);??pool.execute(t3);??pool.execute(t4);??pool.execute(t5);??pool.execute(t6);??//關閉線程池??pool.shutdown();??}?? }?? class?MyRunnable?implements?Runnable{??private?static?AtomicLong?aLong?=newAtomicLong(10000);????????//原子量,每個線程都可以自由操作??private?String?name;??????????//操作人??private?int?x;????????????????//操作數額??MyRunnable(String?name,?int?x)?{??this.name?=?name;??this.x?=?x;??}??public?void?run()?{??System.out.println(name?+?"執行了"?+?x?+",當前余額:"?+?aLong.addAndGet(x));??}?? }??
????????多次執行結果:
?
張三執行了2000,當前余額:12000?? 王五執行了2700,當前余額:14700?? 老張執行了600,當前余額:15300?? 老牛執行了1300,當前余額:20200?? 李四執行了3600,當前余額:18900?? 胖子執行了800,當前余額:21000???
張三執行了2000,當前余額:12000?? 王五執行了2700,當前余額:14700?? 李四執行了3600,當前余額:18300?? 老牛執行了1300,當前余額:20200?? 胖子執行了800,當前余額:21000?? 老張執行了600,當前余額:18900??
????????從運行結果可以看出,雖然使用了原子量,但是程序并發訪問還是有問題,那究竟問題出在哪里了?
????????這里要注意的一點是,原子量雖然可以保證單個變量在某一個操作過程的安全,但無法保證你整個代碼塊,或者整個程序的安全性。因此,通常還應該使用鎖等同步機制來控制整個程序的安全性。
????????下面是對這個錯誤修正:
import?java.util.concurrent.ExecutorService;?? import?java.util.concurrent.Executors;?? import?java.util.concurrent.atomic.AtomicLong;?? import?java.util.concurrent.locks.Lock;?? import?java.util.concurrent.locks.ReentrantLock;??/**?*?Java線程:新特征-原子量?*/?? public?class?Test?{??public?static?void?main(String[]?args){??//創建一個線程池??ExecutorService?pool?=?Executors.newFixedThreadPool(2);??Lock?lock=new?ReentrantLock(false);??Runnable?t1?=?new?MyRunnable("張三",?2000,lock);??Runnable?t2?=?new?MyRunnable("李四",?3600,lock);??Runnable?t3?=?new?MyRunnable("王五",?2700,lock);??Runnable?t4?=?new?MyRunnable("老張",?600,lock);??Runnable?t5?=?new?MyRunnable("老牛",?1300,lock);??Runnable?t6?=?new?MyRunnable("胖子",?800,lock);??//執行各個線程??pool.execute(t1);??pool.execute(t2);??pool.execute(t3);??pool.execute(t4);??pool.execute(t5);??pool.execute(t6);??//關閉線程池??pool.shutdown();??}?? }?? class?MyRunnable?implements?Runnable?{??private?static?AtomicLong?aLong?=newAtomicLong(10000);???//原子量,每個線程都可以自由操作??private?String?name;??????????//操作人??private?int?x;????????????????//操作數額??private?Lock?lock;??MyRunnable(String?name,?int?x,Lock?lock)?{??this.name?=?name;??this.x?=?x;??this.lock=lock;??}??public?void?run()?{??lock.lock();??System.out.println(name?+?"執行了"?+?x?+",當前余額:"?+?aLong.addAndGet(x));??lock.unlock();??}?? }??
????????執行結果:
????????這里使用了一個對象鎖,來控制對并發代碼的訪問。不管運行多少次,執行次序如何,最終余額均為21000,這個結果是正確的。
????????有關原子量的用法很簡單,關鍵是對原子量的認識,原子僅僅是保證變量操作的原子性,但整個程序還需要考慮線程安全的。
?
總結
以上是生活随笔為你收集整理的Java线程详解(17)-原子量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java线程详解(16)-条件变量
- 下一篇: Java线程详解(18)-障碍器