色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

synchronized的原理與四種用法介紹

冬至子 ? 來源:并發編程之美 ? 作者:妙啊 ? 2023-06-09 16:13 ? 次閱讀

介紹

JDK提供的鎖分兩種,一種是JVM實現的synchronized,是java的關鍵字,因此在這個關鍵字作用對象的范圍內都是可以保證原子性的,主要是依賴特殊的CPU指令。另一種是JDK提供的代碼層面的鎖Lock。

一、synchronized的四種用法

1. 修飾代碼塊

大括號括起來的代碼,稱同步語句塊,作用范圍是大括號,作用對象是調用代碼塊的對象。

public void test1(int j) {
    synchronized (this) {
        for (int i = 0; i < 10; i++) {
            log.info("test1 {} - {}", j, i);
        }
    }
}

測試代碼:

public static void main(String[] args) {
    SynchronizedExample1 example1 = new SynchronizedExample1();
    SynchronizedExample1 example2 = new SynchronizedExample1();
    ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.execute(() - > {
        example1.test1(1);
    });
    executorService.execute(() - > {
        example2.test1(2);
    });
}

測試結果:

圖片

  • 可以看到test1方法的參數1和參數2是交替執行。

2. 修飾方法

被修飾的方法稱為同步方法,作用范圍是整個方法,作用于調用對象。

public synchronized void test2(int j) {
    for (int i = 0; i < 10; i++) {
        log.info("test2 {} - {}", j, i);
    }
}

測試代碼:

public static void main(String[] args) {
    SynchronizedExample1 example1 = new SynchronizedExample1();
    SynchronizedExample1 example2 = new SynchronizedExample1();
    ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.execute(() - > {
        example1.test2(1);
    });
    executorService.execute(() - > {
        example2.test2(2);
    });
}

測試結果:

圖片

  • 可以看到test2方法的參數1和參數2是交替執行。

3. 修飾靜態方法

作用范圍是整個方法,作用于所有對象。

public static synchronized void test3(int j) {
    for (int i = 0; i < 10; i++) {
        log.info("test3 {} - {}", j, i);
    }
}

測試代碼:

public static void main(String[] args) {
    SynchronizedExample1 example1 = new SynchronizedExample1();
    SynchronizedExample1 example2 = new SynchronizedExample1();
    ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.execute(() - > {
        example1.test3(1);
    });
    executorService.execute(() - > {
        example2.test3(2);
    });
}

測試結果:

圖片

  • 可以看到test3方法的參數1和參數2是1執行完才執行的2。

4. 修飾類

作用范圍是synchronized后面括號括起來的部分,作用于所有對象。

public static void test4(int j) {
    synchronized (SynchronizedExample2.class) {
        for (int i = 0; i < 10; i++) {
            log.info("test4 {} - {}", j, i);
        }
    }
}

測試代碼:

public static void main(String[] args) {
    SynchronizedExample1 example1 = new SynchronizedExample1();
    SynchronizedExample1 example2 = new SynchronizedExample1();
    ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.execute(() - > {
        example1.test4(1);
    });
    executorService.execute(() - > {
        example2.test4(2);
    });
}

測試結果:

圖片

  • 可以看到test4方法的參數1和參數2是1執行完才執行的2。

二、synchronized的原理

在Java語言中存在兩種內建的synchronized語法:synchronized語句、synchronized方法:

  • synchronized語句:當源代碼被編譯成字節碼的時候,會在同步塊的入口位置和退出位置分別插入monitorenter和monitorexit字節碼指令。
  • synchronized方法:在Class文件的方法表中將該方法的access_flags字段中的synchronized標志位置1

synchronized語句

如上示例,test1和test4使用的就是synchronized語句。使用Javap -c命令反編譯test1代碼,如下:

圖片

在Java虛擬機的specification中,有關于monitorenter和monitorexit字節碼指令的詳細描述:

monitorenter

每個對象都有一個鎖,也就是監視器(monitor)。 Monitor可以理解為一個同步工具或一種同步機制,通常被描述為一個對象。 每一個Java對象就有一把看不見的鎖,稱為內部鎖或者Monitor鎖。

當monitor被占有時就表示它被鎖定。線程執行monitorenter指令時嘗試獲取對象所對應的monitor的所有權,過程如下:

  • 如果monitor的進入數為0,則該線程進入monitor,然后將進入數設置為1,該線程即為monitor的所有者。
  • 如果線程已經擁有了該monitor,只是重新進入,則進入monitor的進入數加1。
  • 如果其他線程已經占用了monitor,則該線程進入阻塞狀態,直到monitor的進入數為0,再重新嘗試獲取monitor的所有權。

monitorexit

執行monitorexit的線程必須是相應的monitor的所有者。指令執行時,monitor的進入數減1,如果減1后進入數為0,那線程退出monitor,不再是這個monitor的所有者。其他被這個monitor阻塞的線程可以嘗試去獲取這個monitor的所有權。

synchronized方法

如上示例,test2和test3使用的就是synchronized方法。synchronized方法加鎖的方式是在Class文件的方法表中將該方法的access_flags字段中的synchronized標志位置1。如下:

圖片

  • 訪問標志的第11位即為加鎖標記位。

三、synchronized的優化

synchronized在操作同步資源之前需要給同步資源先加鎖,這把鎖就是存在Java對象頭里,而Java對象頭又是什么呢?

Java對象頭

以Hotspot虛擬機為例,Hotspot的對象頭主要包括兩部分數據:Mark Word(標記字段)、Klass Pointer(類型指針)。

Mark Word

默認存儲對象的HashCode,分代年齡和鎖標志位信息。這些信息都是與對象自身定義無關的數據,所以Mark Word被設計成一個非固定的數據結構以便在極小的空間內存存儲盡量多的數據。它會根據對象的狀態復用自己的存儲空間,也就是說在運行期間Mark Word里存儲的數據會隨著鎖標志位的變化而變化。

Klass Point

對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。

在JDK1.6及其之前的版本中monitorenter和monitorexit字節碼依賴于底層的操作系統的Mutex Lock來實現的,但是由于使用Mutex Lock需要將當前線程掛起并從用戶態切換到內核態來執行,這種切換的代價是非常昂貴的。然而在現實中的大部分情況下,同步方法是運行在單線程環境(無鎖競爭環境)。如果每次都調用Mutex Lock將嚴重的影響程序的性能。因此在JDK6中為了減少獲得鎖和釋放鎖帶來的性能消耗,引入了偏向鎖輕量級鎖 。所以目前鎖一共有4種狀態,級別從低到高依次是:無鎖、偏向鎖、輕量級鎖和重量級鎖。鎖狀態只能升級不能降級。如下:

圖片

無鎖

  • 無鎖沒有對資源進行鎖定,所有的線程都能訪問并修改同一個資源,但同時只有一個線程能修改成功。
  • 無鎖的特點就是修改操作在循環內進行,線程會不斷的嘗試修改共享資源。如果沒有沖突就修改成功并退出,否則就會繼續循環嘗試。如果有多個線程修改同一個值,必定會有一個線程能修改成功,而其他修改失敗的線程會不斷重試直到修改成功。

偏向鎖

  • 偏向鎖是指一段同步代碼一直被一個線程所訪問,那么該線程會自動獲取鎖,降低獲取鎖的代價。
  • 引入偏向鎖是為了在無多線程競爭的情況下盡量減少不必要的輕量級鎖執行路徑,其目標就是在只有一個線程執行同步代碼塊時能夠提高性能。
  • 當一個線程訪問同步代碼塊并獲取鎖時,會在Mark Word里存儲鎖偏向的線程ID。在線程進入和退出同步塊時不再通過CAS操作來加鎖和解鎖,而是檢測Mark Word里是否存儲著指向當前線程的偏向鎖。
  • 偏向鎖只有遇到其他線程嘗試競爭偏向鎖時,持有偏向鎖的線程才會釋放鎖,線程不會主動釋放偏向鎖。偏向鎖的撤銷,需要等待全局安全點(在這個時間點上沒有字節碼正在執行),它會首先暫停擁有偏向鎖的線程,判斷鎖對象是否處于被鎖定狀態。撤銷偏向鎖后恢復到無鎖或輕量級鎖的狀態。
  • 偏向鎖在JDK 6及以后的JVM里是默認啟用的。可以通過JVM參數關閉偏向鎖: -XX:-UseBiasedLocking=false ,關閉之后程序默認會進入輕量級鎖狀態。

輕量級鎖

  • 是指當鎖是偏向鎖的時候,被另外的線程所訪問,偏向鎖就會升級為輕量級鎖,其他線程會通過自旋的形式嘗試獲取鎖,不會阻塞,從而提高性能。
  • 在代碼進入同步塊的時候,如果同步對象鎖狀態為無鎖狀態(鎖標志位為01狀態,是否為偏向鎖為0),虛擬機首先將在當前線程的棧幀中建立一個名為鎖記錄(Lock Record)的空間,用于存儲鎖對象目前的Mark Word的拷貝,然后拷貝對象頭中的Mark Word復制到鎖記錄中。
  • 拷貝成功后,虛擬機將使用CAS操作嘗試將對象的Mark Word更新為指向Lock Record的指針,并將Lock Record里的owner指針指向對象的Mark Word。
  • 如果這個更新動作成功了,那么這個線程就擁有了該對象的鎖,并且對象Mark Word的鎖標志位設置為00,表示此對象處于輕量級鎖定狀態。
  • 如果輕量級鎖的更新操作失敗了,虛擬機首先會檢查對象的Mark Word是否指向當前線程的棧幀,如果是就說明當前線程已經擁有了這個對象的鎖,那就可以直接進入同步塊繼續執行,否則說明多個線程競爭鎖。

重量級鎖

  • 若當前只有一個等待線程,則該線程通過自旋進行等待。但是當自旋超過一定的次數,或者一個線程在持有鎖,一個在自旋,又有第三個來訪時,輕量級鎖升級為重量級鎖。
  • 升級為重量級鎖時,鎖標志的狀態值變為10,此時Mark Word中存儲的是指向重量級鎖的指針,此時等待鎖的線程都會進入阻塞狀態。

綜上,偏向鎖通過對比Mark Word解決加鎖問題,避免執行CAS操作。而輕量級鎖是通過用CAS操作和自旋來解決加鎖問題,避免線程阻塞和喚醒而影響性能。重量級鎖是將除了擁有鎖的線程以外的線程都阻塞。

四、synchronized存在的問題

1.性能損耗

  • 雖然在JDK 1.6中對synchronized做了很多優化,如如適應性自旋、鎖消除、鎖粗化、輕量級鎖和偏向鎖等,但畢竟還是一種鎖。
  • 所以,無論是使用同步方法還是同步代碼塊,在同步操作之前還是要進行加鎖,同步操作之后需要進行解鎖,這個加鎖、解鎖的過程是要有性能損耗的。

2. 阻塞

  • synchronize實現的鎖本質上是一種阻塞鎖,多個線程要排隊訪問同一個共享對象。
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • JAVA語言
    +關注

    關注

    0

    文章

    138

    瀏覽量

    20113
  • JVM
    JVM
    +關注

    關注

    0

    文章

    158

    瀏覽量

    12238
  • 虛擬機
    +關注

    關注

    1

    文章

    919

    瀏覽量

    28280
  • CAS
    CAS
    +關注

    關注

    0

    文章

    35

    瀏覽量

    15213
收藏 人收藏

    評論

    相關推薦

    四種模擬輸入信號的保護電路實現方法

    本文介紹四種模擬輸入信號的保護電路的實現方法。
    發表于 03-28 09:55 ?1229次閱讀

    FPGA 設計的四種常用思想與技巧

    FPGA 設計的四種常用思想與技巧FPGA設計的四種常用思想與技巧 討論的四種常用FPGA/CPLD設計思想與技巧:乒乓操作、串并轉換、流水線操作、數據接口同步化,都是FPGA/CPLD 邏輯設計
    發表于 08-11 10:30

    四種無線充電技術簡單原理

    詳細介紹了電場耦合 電磁感應 磁共振無線電波 這四種方式
    發表于 07-28 11:12

    四種不同供電模式的LED拓撲介紹

    本文中,小編將為大家介紹四種在LED供電當中經常使用的四種拓撲結構。感興趣的朋友快來看一看吧。 首先需要從了解轉換器的最小及最大輸出電壓入手。這只是將所有LED正向壓降與傳感電阻器電壓相加的總數
    發表于 10-10 15:07

    介紹UPS電源的四種工作方式

    UPS電源是較為常見的應急電源系統,其在市電正常與市電異常的情況下,工作方式也有所不同,以下介紹UPS電源的四種工作方式:正常運行、電池工作、旁路運行和旁路維護。1、正常運行方式 UPS電源系統
    發表于 11-16 06:19

    介紹AUTOSAR支持的四種功能安全機制

    1、AUTOSAR的四種功能安全機制雖然AUTOSAR不是一個完整的安全解決方案,但它提供了一些安全機制用于支持安全關鍵系統的開發。本文用于介紹AUTOSAR支持的四種功能安全機制:內存分區
    發表于 06-10 17:33

    四種典型瞬態介紹

    ,我將介紹應該注意的幾種典型瞬態,以及TI如何幫助滿足瞬態保護需求。 瀏覽此文章,并查看參考設計:《汽車瞬態和過流保護濾波器參考設計》 典型瞬態在四種常見場景中可能會發生瞬變。圖1所示為第一場景
    發表于 11-07 08:02

    無線充電技術的四種方式及其原理和應用介紹

    本文介紹了無線充電技術的應用范圍及其電磁感應方式等四種充電方式的詳細介紹
    發表于 10-12 16:16 ?27次下載
    無線充電技術的<b class='flag-5'>四種</b>方式及其原理和應用<b class='flag-5'>介紹</b>

    jquery四種選擇器介紹

      本文給大家匯總介紹了jQuery的四種選擇器的使用方法以及示例,非常的簡單實用,希望對大家學習jquery能夠有所幫助。
    發表于 12-01 16:40 ?3046次閱讀
    jquery<b class='flag-5'>四種</b>選擇器<b class='flag-5'>介紹</b>

    四種溫度傳感器的數據介紹

    本文檔的主要內容詳細介紹的是四種溫度傳感器的數據介紹包括了:  球形傳感器,卡箍式傳感器,地面傳感器,侵入式傳感器
    發表于 02-28 17:09 ?9次下載

    四種常見的圖像濾波算法介紹

    作者丨一支程序媛@知乎 來源丨https://zhuanlan.zhihu.com/p/279602383 編輯丨極市平臺 導讀 圖像濾波是一非常重要的圖像處理技術,本文詳細介紹四種常見的圖像
    的頭像 發表于 02-15 09:50 ?1w次閱讀

    四種方式實現led點亮

    四種方式實現led點亮
    發表于 01-04 14:31 ?4次下載

    NoSQL數據庫的四種類型

    在本文中,我們將簡要介紹NoSQL數據庫的四種類型。
    的頭像 發表于 04-25 17:21 ?4463次閱讀

    synchronized的鎖膨脹

    初識 synchronized 可以加在方法和類上面,作用于類和對象。下面代碼中列出了 synchronized用法。 public class SynchronizedTest
    的頭像 發表于 10-10 16:58 ?502次閱讀
    <b class='flag-5'>synchronized</b>的鎖膨脹

    介紹MCUboot支持的四種升級模式(2)

    介紹MCUboot支持的四種升級模式,分別是Overwrite、Swap、Direct XIP和加載到RAM中執行。由于FSP不支持第四種——加載到RAM中執行,因為我們重點介紹前三
    的頭像 發表于 06-13 10:56 ?975次閱讀
    <b class='flag-5'>介紹</b>MCUboot支持的<b class='flag-5'>四種</b>升級模式(2)
    主站蜘蛛池模板: 久99re视频9在线观看| 动听968| DASD-700美谷朱里| 国产免费人视频在线观看免费| 国精产品一区二区三区| 免费99精品国产人妻自在线| 手机看片一区二区| 91麻豆久久| 饥渴的护士自慰被发现| 国产伦精品一区二区三区| 伊人久久青青| 一道本在线伊人蕉无码| FREEXXX性乌克兰XXX| 国产精品一区二区20P| 免费一区在线观看| 青青青草免费| 青青草国产自偷拍| 亚洲欧美另类无码专区| 国产成人 免费观看| 欧洲vs美洲完整视频| 色哟哟tv| 高清无码中文字幕影片| 午夜片神马影院福利| 韩国成人理伦片免费播放| 亚洲色图在线观看视频| 看看妇女的B免费看| qvod激情图片| 色噜噜噜视频| 久久精品影院永久网址| 999zyz色资源站在线观看| 日本工口生肉全彩大全| 国产毛A片久久久久久无码| 亚洲精品久久AV无码蜜桃| 浪潮AV色综合久久天堂| xxxxx俄罗斯| 亚洲宅男天堂a在线| 琪琪伦伦影院理论片| 国产午夜电影在线观看不卡| 18未满不能进的福利社| 视频一区国产第一页| 快播可乐网|