国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JAVA并發(fā)編程--2.synchronied實(shí)現(xiàn)原理

mudiyouyou / 1022人閱讀

摘要:實(shí)現(xiàn)原理虛擬機(jī)鎖原理虛擬機(jī)中對(duì)象頭部信息可以看見(jiàn)對(duì)象頭中結(jié)構(gòu)中的成員,允許壓縮。否則,將偏向鎖撤銷,升級(jí)為輕量級(jí)鎖。存在明顯多線程競(jìng)爭(zhēng)的場(chǎng)景下使用偏向鎖是不合適的,例如生產(chǎn)者消費(fèi)者隊(duì)列。

synchronied實(shí)現(xiàn)原理 虛擬機(jī)鎖原理

虛擬機(jī)中對(duì)象頭部信息

/*hotspot/src/share/vm/oops/oop.hpp*/
class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
  union _metadata {
    Klass*      _klass;
    narrowKlass _compressed_klass;
  } _metadata;

可以看見(jiàn)對(duì)象頭中結(jié)構(gòu)

Mark Word:instanceOopDesc中的_mark成員,允許壓縮。它用于存儲(chǔ)對(duì)象的運(yùn)行時(shí)記錄信息,如哈希值、GC分代年齡(Age)、鎖狀態(tài)標(biāo)志(偏向鎖、輕量級(jí)鎖、重量級(jí)鎖)、線程持有的鎖、偏向線程ID、偏向時(shí)間戳等

元數(shù)據(jù)指針:instanceOopDesc中的_metadata成員,它是聯(lián)合體,可以表示未壓縮的Klass指針(_klass)和壓縮的Klass指針。對(duì)應(yīng)的klass指針指向一個(gè)存儲(chǔ)類的元數(shù)據(jù)的Klass對(duì)象

32位的對(duì)象頭結(jié)構(gòu),64位結(jié)構(gòu)略

//  32 bits:
//  --------
//             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
//             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
//             size:32 ------------------------------------------>| (CMS free block)
//             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)

biased_lock 表示是否偏向鎖

lock類型

00 locked 輕量級(jí)鎖

01 unlocked 無(wú)鎖

10 monitor 排他鎖

11 marked 標(biāo)記

加鎖過(guò)程

代碼片段

// 默認(rèn)嘗試偏向鎖
void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) {
 //是否使用偏向鎖
 if (UseBiasedLocking) {
    //未到達(dá)safepoint,嘗試重偏向
    if (!SafepointSynchronize::is_at_safepoint()) {
      BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD);
      if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) {
        return;
      }
    } else { //在safepoint進(jìn)行撤銷偏向鎖
      assert(!attempt_rebias, "can not rebias toward VM thread");
      BiasedLocking::revoke_at_safepoint(obj);
    }
    //如果走到這里則說(shuō)明偏向鎖已撤銷,進(jìn)行slow_enter(加輕量級(jí)鎖)
    assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
 }

 slow_enter (obj, lock, THREAD) ;
}

// 輕量級(jí)鎖
void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
  markOop mark = obj->mark();
  assert(!mark->has_bias_pattern(), "should not see bias pattern here");

  if (mark->is_neutral()) { //如果無(wú)鎖狀態(tài)
    // 在lock對(duì)象上設(shè)置displaced mark word
    lock->set_displaced_header(mark);
    //使用CAS操作交換lock和object的mark word
    if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) {
      TEVENT (slow_enter: release stacklock) ;
      return ;
    }
    // 如果CAS失敗,則跳到下面inflate(重量級(jí)鎖)
  } else
  //如果給相同對(duì)象加鎖,則后續(xù)的鎖的displaced mark設(shè)置為NULL(不會(huì)重復(fù)上鎖)
  if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
    assert(lock != mark->locker(), "must not re-lock the same lock");
    assert(lock != (BasicLock*)obj->mark(), "don"t relock with same BasicLock");
    lock->set_displaced_header(NULL);
    return;
  }
//標(biāo)記lock對(duì)象為unused,后續(xù)由CMS回收,并調(diào)用inflate(重量級(jí)鎖)
lock->set_displaced_header(markOopDesc::unused_mark());
ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
}


偏向鎖

在大多數(shù)情況下,線程之間不存在競(jìng)爭(zhēng)關(guān)系,即一個(gè)鎖會(huì)被某個(gè)線程多次使用。如果每次都需要申請(qǐng)鎖,開(kāi)銷會(huì)比較大。因此出現(xiàn)了偏向鎖,獲取偏向鎖之后,如果是不存在其他線程競(jìng)爭(zhēng)鎖,那么就不需要調(diào)用CAS來(lái)獲取鎖,以達(dá)到減少I/O的目的

加鎖過(guò)程

case 1:當(dāng)該對(duì)象第一次被線程獲得鎖的時(shí)候,發(fā)現(xiàn)是匿名偏向狀態(tài),則會(huì)用CAS指令,將mark word中的thread id由0改成當(dāng)前線程Id。如果成功,則代表獲得了偏向鎖,繼續(xù)執(zhí)行同步塊中的代碼。否則,將偏向鎖撤銷,升級(jí)為輕量級(jí)鎖。

case 2:當(dāng)被偏向的線程再次進(jìn)入同步塊時(shí),發(fā)現(xiàn)鎖對(duì)象偏向的就是當(dāng)前線程,在通過(guò)一些額外的檢查后(細(xì)節(jié)見(jiàn)后面的文章),會(huì)往當(dāng)前線程的棧中添加一條Displaced Mark Word為空的Lock Record中,然后繼續(xù)執(zhí)行同步塊的代碼,因?yàn)椴倏v的是線程私有的棧,因此不需要用到CAS指令;由此可見(jiàn)偏向鎖模式下,當(dāng)被偏向的線程再次嘗試獲得鎖時(shí),僅僅進(jìn)行幾個(gè)簡(jiǎn)單的操作就可以了,在這種情況下,synchronized關(guān)鍵字帶來(lái)的性能開(kāi)銷基本可以忽略。

case 3.當(dāng)其他線程進(jìn)入同步塊時(shí),發(fā)現(xiàn)已經(jīng)有偏向的線程了,則會(huì)進(jìn)入到撤銷偏向鎖的邏輯里,一般來(lái)說(shuō),會(huì)在safepoint中去查看偏向的線程是否還存活,如果存活且還在同步塊中則將鎖升級(jí)為輕量級(jí)鎖,原偏向的線程繼續(xù)擁有鎖,當(dāng)前線程則走入到鎖升級(jí)的邏輯里;如果偏向的線程已經(jīng)不存活或者不在同步塊中,則將對(duì)象頭的mark word改為無(wú)鎖狀態(tài)(unlocked),之后再升級(jí)為輕量級(jí)鎖。

由此可見(jiàn),偏向鎖升級(jí)的時(shí)機(jī)為:當(dāng)鎖已經(jīng)發(fā)生偏向后,只要有另一個(gè)線程嘗試獲得偏向鎖,則該偏向鎖就會(huì)升級(jí)成輕量級(jí)鎖。當(dāng)然這個(gè)說(shuō)法不絕對(duì),因?yàn)檫€有批量重偏向這一機(jī)制。

解鎖過(guò)程

當(dāng)有其他線程嘗試獲得鎖時(shí),是根據(jù)遍歷偏向線程的lock record來(lái)確定該線程是否還在執(zhí)行同步塊中的代碼。因此偏向鎖的解鎖很簡(jiǎn)單,僅僅將棧中的最近一條lock record的obj字段設(shè)置為null。需要注意的是,偏向鎖的解鎖步驟中并不會(huì)修改對(duì)象頭中的thread id。

批量重偏向與撤銷

從上文偏向鎖的加鎖解鎖過(guò)程中可以看出,當(dāng)只有一個(gè)線程反復(fù)進(jìn)入同步塊時(shí),偏向鎖帶來(lái)的性能開(kāi)銷基本可以忽略,但是當(dāng)有其他線程嘗試獲得鎖時(shí),就需要等到safe point時(shí)將偏向鎖撤銷為無(wú)鎖狀態(tài)或升級(jí)為輕量級(jí)/重量級(jí)鎖。safe point這個(gè)詞我們?cè)贕C中經(jīng)常會(huì)提到,其代表了一個(gè)狀態(tài),在該狀態(tài)下所有線程都是暫停的(大概這么個(gè)意思),詳細(xì)可以看這篇文章??傊?,偏向鎖的撤銷是有一定成本的,如果說(shuō)運(yùn)行時(shí)的場(chǎng)景本身存在多線程競(jìng)爭(zhēng)的,那偏向鎖的存在不僅不能提高性能,而且會(huì)導(dǎo)致性能下降。因此,JVM中增加了一種批量重偏向/撤銷的機(jī)制。

存在如下兩種情況:(見(jiàn)官方論文第4小節(jié)):

1.一個(gè)線程創(chuàng)建了大量對(duì)象并執(zhí)行了初始的同步操作,之后在另一個(gè)線程中將這些對(duì)象作為鎖進(jìn)行之后的操作。這種case下,會(huì)導(dǎo)致大量的偏向鎖撤銷操作。

2.存在明顯多線程競(jìng)爭(zhēng)的場(chǎng)景下使用偏向鎖是不合適的,例如生產(chǎn)者/消費(fèi)者隊(duì)列。

批量重偏向(bulk rebias)機(jī)制是為了解決第一種場(chǎng)景。批量撤銷(bulk revoke)則是為了解決第二種場(chǎng)景。

其做法是:以class為單位,為每個(gè)class維護(hù)一個(gè)偏向鎖撤銷計(jì)數(shù)器,每一次該class的對(duì)象發(fā)生偏向撤銷操作時(shí),該計(jì)數(shù)器+1,當(dāng)這個(gè)值達(dá)到重偏向閾值(默認(rèn)20)時(shí),JVM就認(rèn)為該class的偏向鎖有問(wèn)題,因此會(huì)進(jìn)行批量重偏向。每個(gè)class對(duì)象會(huì)有一個(gè)對(duì)應(yīng)的epoch字段,每個(gè)處于偏向鎖狀態(tài)對(duì)象的mark word中也有該字段,其初始值為創(chuàng)建該對(duì)象時(shí),class中的epoch的值。每次發(fā)生批量重偏向時(shí),就將該值+1,同時(shí)遍歷JVM中所有線程的棧,找到該class所有正處于加鎖狀態(tài)的偏向鎖,將其epoch字段改為新值。下次獲得鎖時(shí),發(fā)現(xiàn)當(dāng)前對(duì)象的epoch值和class的epoch不相等,那就算當(dāng)前已經(jīng)偏向了其他線程,也不會(huì)執(zhí)行撤銷操作,而是直接通過(guò)CAS操作將其mark word的Thread Id 改成當(dāng)前線程Id。

當(dāng)達(dá)到重偏向閾值后,假設(shè)該class計(jì)數(shù)器繼續(xù)增長(zhǎng),當(dāng)其達(dá)到批量撤銷的閾值后(默認(rèn)40),JVM就認(rèn)為該class的使用場(chǎng)景存在多線程競(jìng)爭(zhēng),會(huì)標(biāo)記該class為不可偏向,之后,對(duì)于該class的鎖,直接走輕量級(jí)鎖的流程

  product(intx, BiasedLockingBulkRebiasThreshold, 20,       
      "Threshold of number of revocations per type to try to "      
      "rebias all objects in the heap of that type")                

product(intx, BiasedLockingBulkRevokeThreshold, 40,                 
      "Threshold of number of revocations per type to permanently " 
      "revoke biases of all objects in the heap of that type")   
      
輕量級(jí)鎖

加鎖過(guò)程代碼

CASE(_monitorenter): {
    oop lockee = STACK_OBJECT(-1);
    // 創(chuàng)建一個(gè)空堆對(duì)象lockee
    CHECK_NULL(lockee);
    // 遍歷stack中的lock對(duì)象,尋找是否存在指向?qū)ο鬄榇渔i對(duì)象的
    BasicObjectLock* limit = istate->monitor_base();
    BasicObjectLock* most_recent = (BasicObjectLock*) istate->stack_base();
    BasicObjectLock* entry = NULL;
    while (most_recent != limit ) {
      if (most_recent->obj() == NULL) entry = most_recent;
      else if (most_recent->obj() == lockee) break;
      most_recent++;
    }
    if (entry != NULL) { //已存在鎖對(duì)象,構(gòu)建一個(gè)無(wú)鎖狀態(tài)的Displaced Mark Word
    //設(shè)置到Lock Record中去
      entry->set_obj(lockee);
      markOop displaced = lockee->mark()->set_unlocked();
      entry->lock()->set_displaced_header(displaced);
      if (Atomic::cmpxchg_ptr(entry, lockee->mark_addr(), displaced) != displaced) {
        // 如果CAS替換不成功,代表鎖對(duì)象不是無(wú)鎖狀態(tài),這時(shí)候判斷下是不是鎖重入
        if (THREAD->is_lock_owned((address) displaced->clear_lock_bits())) {
          entry->lock()->set_displaced_header(NULL);
        } else {
          // CAS操作失敗則調(diào)用monitorenter
          CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception);
        }
      }
      UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1);
    } else {
      istate->set_msg(more_monitors);
      UPDATE_PC_AND_RETURN(0); // Re-execute
    }
  }

解鎖過(guò)程代碼與加鎖基本相同,省略

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/73021.html

相關(guān)文章

  • 從小白程序員一路晉升為大廠高級(jí)技術(shù)專家我看過(guò)哪些書籍?(建議收藏)

    摘要:大家好,我是冰河有句話叫做投資啥都不如投資自己的回報(bào)率高。馬上就十一國(guó)慶假期了,給小伙伴們分享下,從小白程序員到大廠高級(jí)技術(shù)專家我看過(guò)哪些技術(shù)類書籍。 大家好,我是...

    sf_wangchong 評(píng)論0 收藏0
  • 并發(fā)

    摘要:表示的是兩個(gè),當(dāng)其中任意一個(gè)計(jì)算完并發(fā)編程之是線程安全并且高效的,在并發(fā)編程中經(jīng)常可見(jiàn)它的使用,在開(kāi)始分析它的高并發(fā)實(shí)現(xiàn)機(jī)制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購(gòu),是兩個(gè)比較典型的互聯(lián)網(wǎng)高并發(fā)場(chǎng)景。 干貨:深度剖析分布式搜索引擎設(shè)計(jì) 分布式,高可用,和機(jī)器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽(tīng)名字多牛逼,來(lái),我們一步一步來(lái)?yè)羝魄皟蓚€(gè)名詞,今天我們首先來(lái)說(shuō)說(shuō)分布式。 探究...

    supernavy 評(píng)論0 收藏0
  • 并發(fā)

    摘要:表示的是兩個(gè),當(dāng)其中任意一個(gè)計(jì)算完并發(fā)編程之是線程安全并且高效的,在并發(fā)編程中經(jīng)??梢?jiàn)它的使用,在開(kāi)始分析它的高并發(fā)實(shí)現(xiàn)機(jī)制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購(gòu),是兩個(gè)比較典型的互聯(lián)網(wǎng)高并發(fā)場(chǎng)景。 干貨:深度剖析分布式搜索引擎設(shè)計(jì) 分布式,高可用,和機(jī)器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽(tīng)名字多牛逼,來(lái),我們一步一步來(lái)?yè)羝魄皟蓚€(gè)名詞,今天我們首先來(lái)說(shuō)說(shuō)分布式。 探究...

    ddongjian0000 評(píng)論0 收藏0
  • 并發(fā)

    摘要:表示的是兩個(gè),當(dāng)其中任意一個(gè)計(jì)算完并發(fā)編程之是線程安全并且高效的,在并發(fā)編程中經(jīng)??梢?jiàn)它的使用,在開(kāi)始分析它的高并發(fā)實(shí)現(xiàn)機(jī)制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購(gòu),是兩個(gè)比較典型的互聯(lián)網(wǎng)高并發(fā)場(chǎng)景。 干貨:深度剖析分布式搜索引擎設(shè)計(jì) 分布式,高可用,和機(jī)器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽(tīng)名字多牛逼,來(lái),我們一步一步來(lái)?yè)羝魄皟蓚€(gè)名詞,今天我們首先來(lái)說(shuō)說(shuō)分布式。 探究...

    wangdai 評(píng)論0 收藏0
  • 阿里 2021 版最全 Java 并發(fā)編程筆記,看完我才懂了“內(nèi)卷”的真正意義

    摘要:純分享直接上干貨操作系統(tǒng)并發(fā)支持進(jìn)程管理內(nèi)存管理文件系統(tǒng)系統(tǒng)進(jìn)程間通信網(wǎng)絡(luò)通信阻塞隊(duì)列數(shù)組有界隊(duì)列鏈表無(wú)界隊(duì)列優(yōu)先級(jí)有限無(wú)界隊(duì)列延時(shí)無(wú)界隊(duì)列同步隊(duì)列隊(duì)列內(nèi)存模型線程通信機(jī)制內(nèi)存共享消息傳遞內(nèi)存模型順序一致性指令重排序原則內(nèi)存語(yǔ)義線程 純分享 , 直接上干貨! 操作系統(tǒng)并發(fā)支持 進(jìn)程管理內(nèi)存管...

    不知名網(wǎng)友 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<