Java併發 -- 面向物件
- 面向物件思想裡面有一個很重要的特性: 封裝
- 封裝:將屬性 和實現細節 封裝在物件內部 ,外部物件只能通過目標物件的公共方法 來間接訪問 目標物件的內部屬性
- 利用面向物件 思想寫併發程式 的思路:將共享變數 作為物件屬性 封裝在內部,對所有公共方法 制定 併發訪問策略
Counter
value為共享變數 ,作為Counter的例項屬性 ,將get()和addOne()宣告為synchronized方法 ,Counter就是一個執行緒安全 的類
public class Counter { private long value; public synchronized long get() { return value; } public synchronized long addOne() { return ++value; } }
不可變的共享變數
- 實際場景中,會有很多共享變數,如銀行賬戶有卡號、姓名、身份證、信用額度等,其中卡號、姓名和身份證是不會變的
- 對於不可變的共享變數 ,可以使用final 關鍵字修飾,從而 避免併發問題
識別共享變數間的約束條件
- 共享變數間的約束條件 決定了 併發訪問策略
- 場景:庫存管理中有個合理庫存 的概念,即庫存有一個上限 和一個下限
忽略約束條件
下面程式碼忽略了約束條件:即庫存下限要小於 庫存上限
public class SafeWM { // 庫存下限 private final AtomicLong lower = new AtomicLong(0); // 庫存上限 private final AtomicLong upper = new AtomicLong(0); // 設定庫存下限 public void setLower(long v) { lower.set(v); } // 設定庫存上限 public void setUpper(long v) { upper.set(v); } }
存在竟態條件
public class SafeWM { // 庫存下限 private final AtomicLong lower = new AtomicLong(0); // 庫存上限 private final AtomicLong upper = new AtomicLong(0); // 設定庫存下限 public void setLower(long v) { // 檢驗引數合法性 if (v > upper.get()) { throw new IllegalArgumentException(); } lower.set(v); } // 設定庫存上限 public void setUpper(long v) { // 檢驗引數合法性 if (v < lower.get()) { throw new IllegalArgumentException(); } upper.set(v); } }
- 上述程式碼存在 竟態條件
- 假設庫存的下限和上限分別為2和10,執行緒A呼叫setUpper(5),執行緒B呼叫setLower(7)
- 執行緒A和執行緒B併發執行的結果可能是(7,5),不符合約束條件
使用管程
public class SafeWM { // 庫存下限 private final AtomicLong lower = new AtomicLong(0); // 庫存上限 private final AtomicLong upper = new AtomicLong(0); // 設定庫存下限 public synchronized void setLower(long v) { // 檢驗引數合法性 if (v > upper.get()) { throw new IllegalArgumentException(); } lower.set(v); } // 設定庫存上限 public synchronized void setUpper(long v) { // 檢驗引數合法性 if (v < lower.get()) { throw new IllegalArgumentException(); } upper.set(v); } }
制定併發訪問策略
- 避免共享 :ThreadLocal + 為每個任務分配獨立的執行緒
- 不變模式 :Java領域應用得很少
- 管程和其它同步工具 :管程是萬能解決方案,但針對特定場景,使用JUC提供的讀寫鎖、併發容器等同步工具效能會更好
巨集觀原則
- 優先使用成熟的工具類 (JUC)
- 儘量少使用低階的同步原語 (synchronized、Lock、Semaphore)
- 避免過早優化
轉載請註明出處:http://zhongmingmao.me/2019/05/01/java-concurrent-object-oriented/
訪問原文「Java併發 -- 面向物件」獲取最佳閱讀體驗並參與討論