併發程式設計瑣碎知識點

weixin_34337265發表於2017-03-15

一、執行緒安全

執行緒安全概念:當多個執行緒訪問同一個類(物件或方法)時。這個類始終都能表現出正確的行為,那麼這個類(物件或方法)就是執行緒安全的。
  synchronized:可以在任意物件及方法上加鎖,而加鎖的這段程式碼稱為“互斥區”或“臨界區”。

二、多個執行緒多個鎖

多個執行緒,每個執行緒都可以拿到自己指定的鎖,分別獲得鎖之後,執行 synchronized 方法體的內容。
  關鍵字 synchronize 取得的鎖都是物件鎖,而不是把一段程式碼(方法)當做鎖,哪個執行緒先執行 synchronize 關鍵字的方法,哪個執行緒就持有該方法所屬物件的鎖,兩個物件,執行緒就是獲得兩個不同的鎖,他們互不影響
  有一種情況則是相同的鎖,即在靜態方法上加 synchronize 關鍵字,表示鎖定 .class 類,類級別的鎖(獨佔.class 類)。

三、物件鎖的同步和非同步

同步:synchronized同步的概念就是共享,如果不是共享的資源,就沒有必要進行同步。
  非同步:asynchronized非同步的概念就是獨立,相互之間不受到任何制約。

四、髒讀

在我們對同一個物件的方法加鎖的時候,需要考慮業務的整體性,即為 setValue/getValue 方法同時加鎖 synchronized 同步關鍵字,保證業務(service)的原子性,不然會出現業務錯誤(也從側面保證業務的一致性)。

五、synchronized 其它概念

synchronized 鎖重入:關鍵字 synchronized 擁有鎖重入的功能,也就是在使用 synchronized 時,當一個執行緒得到了一個物件的鎖後,再次請求此物件時是可以再次得到該物件的鎖。出現異常時,鎖自動釋放。
  使用 synchronized 宣告的方法在某些情況下是有弊端的,比如 A 執行緒呼叫同步的方法執行一個很長時間的任務,那麼 B 執行緒就必須等待比較長的時間才能執行,這樣的情況下可以使用 synchronized 程式碼塊去優化程式碼執行時間,也就是通常所說的減少鎖的粒度。

六、volatile 關鍵字的概念

volatile概念:volatile 關鍵字的主要作用是使變數在多個執行緒間可見。  在 Java 中,每一個執行緒都會有一塊工作記憶體區,其中存放著所有執行緒共享的主記憶體中的變數值的拷貝。當執行緒執行時,他在自己的工作記憶體區中操作這些變數。為了存取一個共享的變數,一個執行緒通常先獲取鎖定並去清除它的記憶體工作區,把這些共享變數從所有執行緒的共享記憶體區中正確的裝入到他自己所在的工作記憶體區中,當執行緒解鎖時保證該記憶體區中變數的值寫回到共享記憶體中。
  一個執行緒可以執行的操作有使用(use)、賦值(assign)、裝載(load)、儲存(store)、鎖定(lock)、解鎖(unlock)。  而主記憶體可以執行的操作有讀(read)、寫(write)、鎖定(lock)、解鎖(unlock),每個操作都是原子的。
  volatile 的作用就是強制執行緒到主記憶體(共享記憶體)裡去讀取變數,而不去執行緒工作記憶體區裡去讀取,從而實現了多個執行緒間的變數可見。也就是滿足執行緒安全的可見性。
  volatile 關鍵字雖然擁有多個執行緒之間的可見性,但是卻不具備同步性(也就是原子性),可以算上是一個輕量級的 synchronized ,效能要比 sunchronized 強很多,不會造成阻塞(在很多開源的架構裡,比如 netty 的底層程式碼就大量使用 volatile,可見 netty 效能一定是非常不錯的。)這裡需要注意:一般 volatile 用於只針對多個執行緒可見的變數操作,並不能代替 synchronized 的同步功能。
  volatile 關鍵字只具有可見性,沒有原子性。要實現原子性建議使用 atomic 類的系列物件,支援原子性操作(注意 atomic 類只保證本身方法原子性,並不保證多次操作的原子性。)

七、執行緒之間通訊

使用 wait/notify 方法實現執行緒間的通訊。注意:這兩個方法都是 object 的類的方法,換句話說 Java 為所有的物件都提供了這兩個方法。- 1. wait/notify 必須配合 synchronized 關鍵字使用- 2. wait 方法釋放鎖,notify 方法 不釋放鎖

相關文章