中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何在Java中實現鎖

發布時間:2021-05-27 17:28:03 來源:億速云 閱讀:168 作者:Leah 欄目:編程語言

這篇文章將為大家詳細講解有關如何在Java中實現鎖,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

1. 概述

鎖是Java并發編程中最重要的同步機制。鎖除了讓臨界區互斥執行外,還可以讓釋放鎖的線程獲取同一個鎖的線程發送消息。

2. 鎖的內存語義

  • 當線程獲取鎖時, JMM會把線程對應的本地內存置為無效. 從而使得被監視器保護的臨界區的變量必須從主內存中讀取.

  • 當線程釋放鎖時, JMM會把該線程對應的本地內存中的共享變量刷新到主內存中(并不是不釋放鎖就不刷新到主內存, 只是釋放鎖時把未刷新到主內存中的數據刷新到主內存).

鎖的內存語義與volatile的內存語義

  • 鎖獲取與volatile讀有相同的內存語義.

  • 鎖釋放與volatile寫有相同的內存語義.

內存語義總結

  • 線程A釋放一個鎖, 實質上是線程A向接下來將要獲取這個鎖的某個線程發出了(線程A對共享變量所做修改的)消息.

  • 線程B獲取一個鎖, 實質上是線程B接收了之前某個線程發出的(在釋放這個鎖之前對共享變量所做修改的)消息.

  • 線程A釋放鎖, 隨后線程B獲取這個鎖, 這個過程實質上是線程A通過主內存向線程B發送消息.

3. 鎖內存語義的實現

下面以ReentrantLock為例, 獲取到鎖就是把state改為1(不考慮重入), 釋放鎖時改為0.

而加鎖的關鍵代碼就是

protected final boolean compareAndSetState(int expect, int update) {
 return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

該方法以原子操作的方式更新state變量, 本文把Java的compareAndSet()方法簡稱為CAS. JDK文檔對該方法的說明如下: 如果當前狀態值等于預期值, 則以原子方式將同步狀態設置為給定的更新值. 此操作具有volatile讀和寫的內存語義.

這里我們分別從編譯器和處理器的角度來分析: CAS如何同時具有volatile讀和volatile寫的內存語義.

我們知道, 編譯器不會對volatile讀與volatile讀后面的任意內存操作重排序; 編譯器不會對volatile寫與volatile寫前面的任意內存操作重排序. 組合這兩個條件, 意味著為了同時實現volatile讀和volatile寫的內存語義, 編譯器不能對CAS與CAS前面和后面的任意內存操作重排序.

下面我們來分析在常見的intel X86處理器中, CAS是如何同時具有volatile讀和volatile寫的內存語義的.

下面是sun.misc.Unsafe類的compareAndSwapInt()方法的源代碼.

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

可以看到, 這是一個本地方法調用. 這個本地方法在openjdk中依次調用的c++代碼為: unsafe.cpp, atomic.cpp 和 atomic_windows_x86.inline.hpp. 這個本地方法的最終實現在openjdk的如下位置: openjdk-7-fcs-src-b147-
27_jun_2011\openjdk\hotspot\src\os_cpu\windows_x86\vm\atomic_windows_x86.inline.hpp(對應于
Windows操作系統, X86處理器). 下面是對應于intel X86處理器的源代碼的片段.

inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) {
 // alternative for InterlockedCompareExchange
 int mp = os::is_MP();
 __asm {
  mov edx, dest
  mov ecx, exchange_value
  mov eax, compare_value
  LOCK_IF_MP(mp)
  cmpxchg dword ptr [edx], ecx
 }
}

如上面源代碼所示, 程序會根據當前處理器的類型來決定是否為cmpxchg指令添加lock前綴. 如果程序是在多處理器上運行, 就為cmpxchg指令加上lock前綴(Lock Cmpxchg). 反之, 如果程序是在單處理器上運行, 就省略lock前綴(單處理器自身會維護單處理器內的順序一致性, 不需要lock前綴提供的內存屏障效果).

intel的手冊對lock前綴的說明如下.

  • 確保對內存的讀-改-寫操作原子執行. 在Pentium及Pentium之前的處理器中, 帶有lock前綴的指令在執行期間會鎖住總線, 使得其他處理器暫時無法通過總線訪問內存. 很顯然, 這會帶來昂貴的開銷. 從Pentium 4、Intel Xeon及P6處理器開始, Intel使用緩存鎖定(Cache Locking)
     來保證指令執行的原子性. 緩存鎖定將大大降低lock前綴指令的執行開銷.

  • 禁止該指令, 與之前和之后的讀和寫指令重排序.

  • 把寫緩沖區中的所有數據刷新到內存中.

關于如何在Java中實現鎖就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

陵川县| 唐河县| 云龙县| 额尔古纳市| 星座| 龙陵县| 高陵县| 苍梧县| 四川省| 贵州省| 桂平市| 平乡县| 宾阳县| 长武县| 周口市| 咸阳市| 九龙城区| 河池市| 砚山县| 台南县| 凌源市| 荥阳市| 内江市| 射洪县| 澄城县| 华阴市| 从化市| 沂水县| 景德镇市| 平潭县| 凤台县| 大宁县| 葵青区| 定边县| 林口县| 曲水县| 临邑县| 花莲县| 陆丰市| 景东| 麻城市|