<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      synchronized 原理 (偏向鎖、輕量級鎖、鎖膨脹、自旋)

      synchronized 原理

      Synchronized 是 Java 中用于實現(xiàn)線程同步的關(guān)鍵字,它可以用于方法或代碼塊。當一個方法或代碼塊被 synchronized 修飾時,它將在任意時刻只允許一個線程訪問,保證了多線程環(huán)境下的數(shù)據(jù)安全性。
      synchronized可用于修飾對象或方法:

      方法上的 synchronized

      class Test{
           public synchronized void test() {
      				// ...
           }
      }
      // 等價于
      class Test{
           public void test() {
               synchronized(this) {
                   // ...
               }
           }
      }
      
      class Test{
           public synchronized static void test() {
               // ...
           }
      }
      // 等價于
      class Test{
           public static void test() {
               synchronized(Test.class) {
      						// ...
               }
           }
      }
      

      對象上的 synchronized

      synchronized(對象) // 線程1,線程2(blocked)
      {
      		臨界區(qū)
      }
      
      static int counter = 0;
          static final Object room = new Object();
          public static void main(String[] args) throws InterruptedException {
              Thread t1 = new Thread(() -> {
                  for (int i = 0; i < 5000; i++) {
                      synchronized (room) {
                          counter++;
                      }
                  }
              }, "t1");
              Thread t2 = new Thread(() -> {
                  for (int i = 0; i < 5000; i++) {
                      synchronized (room) {
                          counter--;
                      }
                  }
              }, "t2");
              t1.start();
              t2.start();
              t1.join();
              t2.join();
              log.debug("{}",counter);
          }
      

      synchronized 實際是用對象鎖保證了臨界區(qū)內(nèi)代碼的原子性,臨界區(qū)內(nèi)的代碼對外是不可分割的,不會被線程切換所打斷。

      偏向鎖

      一開始沒有競爭時,加的是偏向鎖。 Java 6 中引入了偏向鎖來做進一步優(yōu)化:只有第一次使用 CAS 將線程 ID 設(shè)置到對象的 Mark Word 頭,之后發(fā)現(xiàn)這個線程 ID 是自己的就表示沒有競爭,不用重新 CAS。以后只要不發(fā)生競爭,這個對象就歸該線程所有

      對象頭格式:
      image

      一個對象創(chuàng)建時:

      • 如果開啟了偏向鎖(默認開啟),那么對象創(chuàng)建后,markword 值為 0x05 即最后 3 位為 101,這時它的 thread、epoch、age 都為 0
      • 偏向鎖是默認是延遲的,不會在程序啟動時立即生效,如果想避免延遲,可以加 VM 參數(shù) - XX:BiasedLockingStartupDelay=0 來禁用延遲
      • 如果沒有開啟偏向鎖,那么對象創(chuàng)建后,markword 值為 0x01 即最后 3 位為 001,這時它的 hashcode、 age 都為 0,第一次用到 hashcode 時才會賦值

      撤銷 - 調(diào)用對象 hashCode

      調(diào)用了對象的 hashCode,但偏向鎖的對象 MarkWord 中存儲的是線程 id,如果調(diào)用 hashCode 會導致偏向鎖被撤銷

      • 輕量級鎖會在鎖記錄中記錄 hashCode
      • 重量級鎖會在 Monitor 中記錄 hashCode

      在調(diào)用 hashCode 后使用偏向鎖,記得去掉 -XX:-UseBiasedLocking

      撤銷 - 其它線程使用對象

      當有其它線程使用偏向鎖對象時,會將偏向鎖升級為輕量級鎖

      撤銷 - 調(diào)用 wait/notify

      偏向鎖或者輕量級鎖,在調(diào)用了 wait 方法之后均會直接膨脹為重量級鎖。具體可以查看下面這篇對重量級鎖底層源碼的解析,其中有提到:

      如果線程獲得鎖后調(diào)用Object#wait方法,則會將線程加入到WaitSet中,當被Object#notify喚醒后,會將線程從WaitSet移動到cxq或EntryList中去。需要注意的是,當調(diào)用一個鎖對象的waitnotify方法時,如當前鎖的狀態(tài)是偏向鎖或輕量級鎖則會先膨脹成重量級鎖。

      批量重偏向

      如果對象雖然被多個線程訪問,但沒有競爭,這時偏向了線程 T1 的對象仍有機會重新偏向 T2,重偏向會重置對象 的 Thread ID

      當撤銷偏向鎖閾值超過 20 次后,jvm 會這樣覺得,我是不是偏向錯了呢,于是會在給這些對象加鎖時重新偏向至加鎖線程

      批量撤銷

      當撤銷偏向鎖閾值超過 40 次后,jvm 會這樣覺得,自己確實偏向錯了,根本就不該偏向。于是整個類的所有對象 都會變?yōu)椴豢善虻模陆ǖ膶ο笠彩遣豢善虻?/p>

      參考資料 https://github.com/farmerjohngit/myblog/issues/12 http://www.rzrgm.cn/LemonFive/p/11246086.html http://www.rzrgm.cn/LemonFive/p/11248248.html 偏向鎖論文

      輕量級鎖

      輕量級鎖的使用場景:如果一個對象雖然有多線程要加鎖,但加鎖的時間是錯開的(也就是沒有競爭),那么可以使用輕量級鎖來優(yōu)化。

      輕量級鎖對使用者是透明的,即語法仍然是 synchronized

      假設(shè)有兩個方法同步塊,利用同一個對象加鎖

      • 創(chuàng)建鎖記錄(Lock Record)對象,每個線程都的棧幀都會包含一個鎖記錄的結(jié)構(gòu),內(nèi)部可以存儲鎖定對象的 Mark Word
      • 讓鎖記錄中 Object reference 指向鎖對象,并嘗試用 cas 替換 Object 的 Mark Word,將 Mark Word 的值存 入鎖記錄
      • 如果 cas 替換成功,對象頭中存儲了 鎖記錄地址和狀態(tài) 00 ,表示由該線程給對象加鎖
      • 如果 cas 失敗,有兩種情況
        • 如果是其它線程已經(jīng)持有了該 Object 的輕量級鎖,這時表明有競爭,進入鎖膨脹過程
        • 如果是自己執(zhí)行了 synchronized 鎖重入,那么再添加一條 Lock Record 作為重入的計數(shù)
      • 當退出 synchronized 代碼塊(解鎖時)如果有取值為 null 的鎖記錄,表示有重入,這時重置鎖記錄,表示重入計數(shù)減一
      • 當退出 synchronized 代碼塊(解鎖時)鎖記錄的值不為 null,這時使用 cas 將 Mark Word 的值恢復給對象頭
        • 成功,則解鎖成功
        • 失敗,說明輕量級鎖進行了鎖膨脹或已經(jīng)升級為重量級鎖,進入重量級鎖解鎖流程

      鎖膨脹

      如果在嘗試加輕量級鎖的過程中,CAS 操作無法成功,這時一種情況就是有其它線程為此對象加上了輕量級鎖(有競爭),這時需要進行鎖膨脹,將輕量級鎖變?yōu)橹亓考夋i。

      • 當 Thread-1 進行輕量級加鎖時,Thread-0 已經(jīng)對該對象加了輕量級鎖
      • 這時 Thread-1 加輕量級鎖失敗,進入鎖膨脹流程
        • 即為 Object 對象申請 Monitor 鎖,讓 Object 指向重量級鎖地址
        • 然后自己進入 Monitor EntryList BLOCKED
      • 當 Thread-0 退出同步塊解鎖時,使用 cas 將 Mark Word 的值恢復給對象頭,失敗。這時會進入重量級解鎖 流程,即按照 Monitor 地址找到 Monitor 對象,設(shè)置 Owner 為 null,喚醒 EntryList 中 BLOCKED 線程
        (對于對象的hashcode,輕量級鎖會將存儲在棧幀的鎖記錄里 重量級鎖存儲在monitor里)

      自旋優(yōu)化

      重量級鎖競爭的時候,還可以使用自旋來進行優(yōu)化,如果當前線程自旋成功(即這時候持鎖線程已經(jīng)退出了同步塊,釋放了鎖),這時當前線程就可以避免阻塞。

      • 自旋會占用 CPU 時間,單核 CPU 自旋就是浪費,多核 CPU 自旋才能發(fā)揮優(yōu)勢。

      • 在 Java 6 之后自旋鎖是自適應的,比如對象剛剛的一次自旋操作成功過,那么認為這次自旋成功的可能性會高,就多自旋幾次;反之,就少自旋甚至不自旋,總之,比較智能。

      • Java 7 之后不能控制是否開啟自旋功能

      總結(jié)

      鎖的升級流程:無鎖 --> 偏向鎖 --> (有競爭時先進行一次CAS,失敗后鎖膨脹)重量級鎖

      posted @ 2024-02-27 10:57  komushdjk  閱讀(222)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲ⅴa曰本va欧美va视频| 视频一区二区三区刚刚碰| 日日碰狠狠躁久久躁96avv| 亚洲综合网国产精品一区| av日韩在线一区二区三区| 国产稚嫩高中生呻吟激情在线视频| 亚洲精品中文字幕一区二| 久久精品国产亚洲av麻豆长发| 日韩人妻无码一区二区三区99| 双辽市| 日韩高清在线亚洲专区不卡| 午夜成人性爽爽免费视频| 国产成人一区二区不卡| 国产蜜臀在线一区二区三区 | 97久久综合亚洲色hezyo| 久久免费精品国自产拍网站| 影音先锋在线资源无码| av在线播放观看国产| 亚洲色大成网站www看下面| 四虎影视库国产精品一区| 国产一区日韩二区欧美三区| 国精品午夜福利视频不卡| 樱桃视频影院在线播放| 国产亚洲精品久久久久久久软件 | 最新精品露脸国产在线| 精品国产午夜福利在线观看| 精品国产一区二区亚洲人| 亚洲熟妇精品一区二区| 亚洲性日韩精品一区二区三区| 一区二区三区午夜福利院| 18岁日韩内射颜射午夜久久成人| 好吊视频专区一区二区三区| 日韩一区在线中文字幕| 闻喜县| 乱人伦人妻中文字幕在线| 做暖暖视频在线看片免费 | 亚洲精品一区国产精品| 男人av无码天堂| 一区二区三区成人| 中文字幕日韩有码国产| 九江县|