第二章:Java併發機制的底層實現原理

一、volatile的應用

volatile是輕量級的synchronized,在多線程中保證了共享變量的"可見性"。如果volatile變量修飾符使用恰當的話,它比synchronized的使用和執行成本更低,因爲它不會引起線程上下文的切換和調度

volatile的定義與實現原理

volatile修飾的共享變量,在多核處理器下會引發兩件事情:

  • 將當前處理器緩存航的數據寫會到系統內存
  • 這個寫回內存的操作會使在其他CPU裏緩存了該內存地址的數據無效

爲了提高處理速度,處理器不直接和內存進行通信,而是先將系統內存的數據讀到緩存後再進行操作,但操作完不知道何時會寫到內存。如果對聲明瞭volatile的變量進行寫操作,JVM就會向處理器發送一條Lock前綴的指令,將這個變量所在緩存行的數據寫回到系統內存。同時其他處理器會將緩存中該變量的數據置爲無效(緩存一致性協議),從內存中重新讀取;

volatile的使用優化

舉例:
隊列集合:LinkedTransferQueue 使用追加字節的方式優化隊列的出隊和入隊性能;

並不是所有的使用volatile的變量都應該追加到64個字節:
追加字節,與處理器的緩存行處理字節數相關,有些處理器的緩存行是32個字節寬,就沒有必要增加字節;
如果共享變量不會被頻繁的寫,鎖機率非常小,也沒有必要通過追加字節的方式來避免相互鎖定;

二、Synchronized的實現原理和應用

synchronized實現同步的基礎,Java中的每一個對象都可以作爲鎖,具體表現爲下面三種形式:

  • 對於普通同步方法,鎖時當前實力對象
  • 對於靜態同步方法,鎖時當前類的Class對象
  • 對於同步方法塊,鎖時Synchronized括號裏配置的對象

Java對象頭

synchronized用的鎖是存儲在對象頭中的;如果對象是數組類型,則虛擬機用3個字節寬存儲對象頭,如果對象是非數組類型,則用2個字節寬存儲對象頭;

鎖的升級與對比

JavaSE1.6爲了減少獲得鎖和釋放鎖帶來的性能消耗,引入了"偏向鎖"和"輕量級鎖";在JavaSE1.6中,鎖一共有4種狀態,級別從低到高依次是:無鎖狀態、偏向鎖、輕量級鎖、重量級鎖,這幾個狀態會隨着競爭情況逐漸升級;
鎖可以升級,但不能降級,目的是爲了提高獲得鎖和釋放鎖的效率;

鎖的優缺點與對比

優點 缺點 適用場景
偏向鎖 加鎖和解鎖不需要額外的消耗,和執行非同步方法相比僅存在納秒級的差距 如果線程間存在鎖競爭,會帶來額外的鎖撤銷的消耗 適用於只有一個線程訪問同步塊場景
輕量級鎖 競爭的線程不會阻塞,提高了程序的響應速度 如果始終得不到鎖競爭的線程,使用自旋會消耗CPU 追求響應時間,同步塊執行速度非常快
重量級鎖 線程競爭不適用自旋,不會消耗CPU 線程阻塞,響應時間慢 追求吞吐量,同步塊響應時間長

Java如何實現原子操作

  • 使用CAS實現原子操作
    JDK併發包裏提供了一些使用CAS支持原子操作的類,如:AtomicBoolean,AtomicInteger,AtomicLong,同時提供了有用的工具方法,比如自增、自減;

  • 使用鎖機制實現原子操作

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