Java線程安全性

      在Java中,線程安全性是指:當多個線程訪問某個類時,不管運行時環境採用何種調度方式或者這些進程將如何交替進行,並且在主調代碼中不需要任何額外的同步或協同,這個類都能表現出正確的行爲,那麼就稱這個類是線程安全的。

      線程安全性體現在三個方面:原子性、可見性、有序性。

一. 原子性

      原子性提供了互斥訪問,同一時刻只能有一個線程來對它進行操作。

      保證原子性有兩種方式:

      (1)Atomic包

  • AtomicXXX:CAS、Unsafe.compareAndSwapInt
  • AtomicLong、LongAdder(兩者區別:https://blog.csdn.net/yao123long/article/details/63683991
  • AtomicReference、AtomicReferenceFieldUpdater(添加的類屬性需要使用volatile修飾)
  • AtomicStampReference:解決CAS的ABA問題

      (2)鎖

  • synchronized:依賴JVM,修飾代碼塊、方法、靜態方法、類(子類繼承父類後,父類的synchronized修飾的方法不起作用(synchronized不屬於方法聲明的一部分),子類需要自己顯式聲明synchronized關鍵字。)
  • Lock:依賴特殊的CPU指令,代碼實現,ReentrantLock

二. 可見性

     可見性指一個線程對主內存的修改可以及時的被其他線程觀察到。

     volatile:通過加入內存屏障禁止重排序優化來實現。(不保證原子性)

  • 對volatile變量寫操作時,會在寫操作後加入一條store屏障指令,將本地內存中的共享變量值刷新到主內存;
  • 對volatile變量讀操作時,會在讀操作前加入一條load屏障指令,從主內存中讀取共享變量。

     使用volatile必須具備2個條件:①對變量的寫操作不依賴當前值;②該變量沒有包含在具有其他變量的不變式中。

三. 有序性

      有序性指一個線程觀察其他線程中的指令執行順序,由於指令重排序的存在,該觀察結果一般雜亂無序。

      happens-before原則保證指令不能重排,共有8條原則:

  • 程序順序原則:一個線程內保證語義的串行性。
  • volatile規則:volatile變量的寫,先發生於讀,這保證了volatile變量的可見性。
  • 鎖規則:解鎖(unlock)必然發生在隨後的加鎖(lock)前。
  • 傳遞性:A先於B,B先於C,那麼A必然先於C。
  • 線程的start()方法先於它的每一個動作。
  • 線程的所有操作先於線程的終結(Thread.join())。
  • 線程的中斷(interrupt())先於被中斷線程的代碼。
  • 對象的構造函數執行、結束先於finalize()方法。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章