volatile 的高階模式

2021-09-01 03:38:32 字數 1235 閱讀 7654

前面幾節介紹的模式涵蓋了大部分的基本用例,在這些模式中使用 volatile 非常有用並且簡單。這一節將介紹一種更加高階的模式,在該模式中,volatile 將提供效能或可伸縮性優勢。

volatile 應用的的高階模式非常脆弱。因此,必須對假設的條件仔細證明,並且這些模式被嚴格地封裝了起來,因為即使非常小的更改也會損壞您的**!同樣,使用更高階的 volatile 用例的原因是它能夠提公升效能,確保在開始應用高階模式之前,真正確定需要實現這種效能獲益。需要對這些模式進行權衡,放棄可讀性或可維護性來換取可能的效能收益 —— 如果您不需要提公升效能(或者不能夠通過乙個嚴格的測試程式證明您需要它),那麼這很可能是一次糟糕的交易,因為您很可能會得不償失,換來的東西要比放棄的東西價值更低。

[b]模式 #5:開銷較低的讀-寫鎖策略[/b]

目前為止,您應該了解了 volatile 的功能還不足以實現計數器。因為 ++x 實際上是三種操作(讀、新增、儲存)的簡單組合,如果多個執行緒湊巧試圖同時對 volatile 計數器執行增量操作,那麼它的更新值有可能會丟失。

然而,如果讀操作遠遠超過寫操作,您可以結合使用內部鎖和 volatile 變數來減少公共**路徑的開銷。清單 6 中顯示的執行緒安全的計數器使用 synchronized 確保增量操作是原子的,並使用 volatile 保證當前結果的可見性。如果更新不頻繁的話,該方法可實現更好的效能,因為讀路徑的開銷僅僅涉及 volatile 讀操作,這通常要優於乙個無競爭的鎖獲取的開銷。

[b]清單 6. 結合使用 volatile 和 synchronized 實現 「開銷較低的讀-寫鎖」 [/b]

@threadsafe

public class cheesycounter

public synchronized int increment()

}

之所以將這種技術稱之為 「開銷較低的讀-寫鎖」 是因為您使用了不同的同步機制進行讀寫操作。因為本例中的寫操作違反了使用 volatile 的第乙個條件,因此不能使用 volatile 安全地實現計數器 —— 您必須使用鎖。然而,您可以在讀操作中使用 volatile 確保當前值的可見性,因此可以使用鎖進行所有變化的操作,使用 volatile 進行唯讀操作。其中,鎖一次只允許乙個執行緒訪問值,volatile 允許多個執行緒執行讀操作,因此當使用 volatile 保證讀**路徑時,要比使用鎖執行全部**路徑獲得更高的共享度 —— 就像讀-寫操作一樣。然而,要隨時牢記這種模式的弱點:如果超越了該模式的最基本應用,結合這兩個競爭的同步機制將變得非常困難。

volatile與單例模式

參考文獻 volatile關鍵字的作用 原理 保持記憶體可見性 所有執行緒都能看到共享資料的最新值。防止指令重排序。1 讀取前先從記憶體重新整理最新的值。2 寫入後立即同步回記憶體中。插入記憶體屏障來禁止重排序。例如 下面是基於保守策略的jmm記憶體屏障插入策略 在每個volatile寫操作的前面插...

(一)設計模式之單例模式 volatile

簡單理解 在記憶體中某個例項物件只有乙個,並由程式程序中的其他執行緒共享該例項。1 了解物件建立過程 第一步 分配記憶體空間 第二步 呼叫建構函式,初始化例項。2 禁止指令重排序 當建構函式在物件初始化的完成之前就完成了物件賦值,在記憶體中開闢一片儲存區域後直接返回記憶體的引用,但是這個時候還沒正真...

單例模式 雙層檢驗鎖 volatile

package com.utils.threads public class dl return instance public static void main string args 分析 加volatile的必要性 原因在於指令重排的存在,加入volatile可以禁止指令重排 當某乙個執行緒執...