《Java併發編程實戰》第3章-對象的共享

0.概念理解

對象狀態:就是對象當中的各個成員變量;
對象發佈:就是將對象的引用交給別人;
安全發佈:創建對象需要一段時間,等徹底創建完了才把引用給別人(其他線程);
逸出/逃逸:不應該發佈的對象被髮布了;
不正確構造:this在構造過程中逸出(即使在構造函數最後一行也不行);
線程封閉:不要讓不安全的對象被多線程共享;
不可變對象:只有一種狀態的對象;
事實不可變對象:狀態在發佈後不會改變的可變對象;

1.爲甚麼存在對象共享的問題?

多個線程之間需要通信,需要操作同一組數據,以達到多線程協作的目的。

2.多線程之間共享對象時會存在什麼樣的問題?
  • 線程A在使用對象狀態的同時線程B在修改對象狀態,導致使用時讀取到的對象狀態是新老版本各一半,造成錯誤;
  • 一個線程在修改了對象狀態後,其他線程不能夠及時看到。
3.volatile的原理與應用
  • 原理:禁止指令重排,禁用寄存器等線程間不共享的緩存,不加鎖不阻塞,成本只是略高;
  • 應用:作爲狀態標記以判斷是否退出循環;
4.發佈對象的幾種情況
  • 將對象引用保存至公有靜態變量;
  • 從非私有方法中返回一個引用;
  • 傳遞發佈:發佈對象的公有域都會被髮布;
  • 發佈一個內部類實例(隱含引用外部類this),不正確構造;
5.線程封閉的方式、應用場景與注意事項
  • 方式:
  • Ad-hoc(自己注意)、棧封閉(局部變量)、ThreadLocal(資源副本)
  • 應用場景:
  • Swing的可視化組件與數據模型的事件分發線程;
  • JDBC的Connection對象;
  • 注意:
  • 防止逸出:不要讓外部傳入的對象引用到棧內對象;
  • ThreadLocal僅僅用在分配操作開銷高的對象上,否則用棧封閉即可;
  • ThreadLocal的濫用:將使用該機制的代碼與框架代碼耦合,在類之間引入隱含的耦合性,降低代碼可重用性;
6.不可變對象不變性條件
  • 對象創建以後其狀態就不能修改;
  • 對象的所有域都是final類型;
  • 對象是正確創建的(構造時this未逸出);
7.使用volatile+不可變對象保證線程安全的原理

不可變對象作爲容器存放多個狀態,要同步改動所有狀態只有一種方式:重新new一個容器不可變對象,再把引用指過去,要及時可見則加volatile;

8.安全發佈的幾種辦法
  • 在靜態初始化函數中初始化一個對象引用;
  • 將對象引用保存在volatile或AtomicReference對象中;
  • 將對象引用保存到某個正確構造對象的final域中;
  • 將對象引用保存到一個由鎖保護的域中;
9.保證線程安全地共享對象的幾種方法
  • 線程封閉:修改操作封閉在單線程;
  • ThreadLocal
  • volatile+發佈不可變對象
  • 安全發佈事實不可變對象
其他需要注意的問題
  • 若無同步,編譯器、處理器以及運行時都可能對操作執行順序進行重排;
  • long與double寫操作非原子,需要加volatile或鎖;
  • 服務端程序調試啓動JVM必須加-server;
  • 在構造函數中調用可改寫方法可能使this逸出,可使用私有構造函數和公共工廠方法,確保初始化好了之後再發布;
  • Java內存模型中,final域能保證初始化過程安全性,也就是正確創建;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章