成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java 中關(guān)于鎖的一些理解

Yumenokanata / 3104人閱讀

摘要:每一個被鎖住的對象都會和一個關(guān)聯(lián)對象頭的中的指向的起始地址,同時中有一個字段存放擁有該鎖的線程的唯一標(biāo)識,表示該鎖被這個線程占用。

jdk 6 對鎖進行了優(yōu)化,讓他看起來不再那么笨重,synchronized有三種形式:偏向鎖,輕量級鎖,重量級鎖.

介紹三種鎖之前,引入幾個接下來會出現(xiàn)的概念

mark work:
對象頭,對象頭中存儲了一些對象的信息,這個是鎖的根本,任何鎖都需要依賴mark word 來維持鎖的運作,對象頭中存儲了當(dāng)前持有鎖的線程,hashCode,GC的一些信息都存儲在對象頭中.
在JVM中,對象在內(nèi)存中除了本身的數(shù)據(jù)外還會有個對象頭,對于普通對象而言,其對象頭中有兩類信息:mark word和類型指針。另外對于數(shù)組而言還會有一份記錄數(shù)組長度的數(shù)據(jù).
類型指針是指向該對象所屬類對象的指針,mark word用于存儲對象的HashCode、GC分代年齡、鎖狀態(tài)等信息。在32位系統(tǒng)上mark word長度為32bit,64位系統(tǒng)上長度為64bit。為了能在有限的空間里存儲下更多的數(shù)據(jù),其存儲格式是不固定的,在32位系統(tǒng)上各狀態(tài)的格式如下:

可以看到鎖信息也是存在于對象的mark word中的。當(dāng)對象狀態(tài)為偏向鎖時,mark word存儲的是偏向的線程ID;當(dāng)狀態(tài)為輕量級鎖時,mark word存儲的是指向線程棧中Lock Record的指針;當(dāng)狀態(tài)為重量級鎖時,為指向堆中的monitor對象的指針.

Lock Record:
前面對象頭中提到了Lock Record,接下來說下Lock Record,Lock Record存在于線程棧中,翻譯過來就是鎖記錄,它會拷貝一份對象頭中的mark word信息到自己的線程棧中去,這個拷貝的mark word 稱為Displaced Mark Word ,另外還有一個指針指向?qū)ο?/p>

monitor:
monitor存在于堆中,什么是Monitor?我們可以把它理解為一個同步工具,也可以描述為一種同步機制,它通常被描述為一個對象。

與一切皆對象一樣,所有的Java對象是天生的Monitor,每一個Java對象都有成為Monitor的潛質(zhì),因為在Java的設(shè)計中 ,每一個Java對象自打娘胎里出來就帶了一把看不見的鎖,它叫做內(nèi)部鎖或者Monitor鎖。

Monitor 是線程私有的數(shù)據(jù)結(jié)構(gòu),每一個線程都有一個可用monitor record列表,同時還有一個全局的可用列表。每一個被鎖住的對象都會和一個monitor關(guān)聯(lián)(對象頭的MarkWord中的LockWord指向monitor的起始地址),同時monitor中有一個Owner字段存放擁有該鎖的線程的唯一標(biāo)識,表示該鎖被這個線程占用。其結(jié)構(gòu)如下:

Owner:初始時為NULL表示當(dāng)前沒有任何線程擁有該monitor record,當(dāng)線程成功擁有該鎖后保存線程唯一標(biāo)識,當(dāng)鎖被釋放時又設(shè)置為NULL

EntryQ:關(guān)聯(lián)一個系統(tǒng)互斥鎖(semaphore),阻塞所有試圖鎖住monitor record失敗的線程

RcThis:表示blocked或waiting在該monitor record上的所有線程的個數(shù)

Nest:用來實現(xiàn)重入鎖的計數(shù)

HashCode:保存從對象頭拷貝過來的HashCode值(可能還包含GC age)

Candidate:用來避免不必要的阻塞或等待線程喚醒,因為每一次只有一個線程能夠成功擁有鎖,如果每次前一個釋放鎖的線程喚醒所有正在阻塞或等待的線程,會引起不必要的上下文切換(從阻塞到就緒然后因為競爭鎖失敗又被阻塞)從而導(dǎo)致性能嚴重下降。Candidate只有兩種可能的值0表示沒有需要喚醒的線程1表示要喚醒一個繼任線程來競爭鎖
(摘自:Java中synchronized的實現(xiàn)原理與應(yīng)用)

說完幾個關(guān)鍵概念之后來說一下鎖的問題:

偏向鎖
偏向鎖是鎖的級別中最低的鎖,舉個例子: 在此demo中,獲得操作list的一直都是main線程,沒有第二個線程參與操作,此時的鎖就是偏向鎖,偏向鎖很輕,jdk 1.6默認開啟,當(dāng)?shù)谝粋€線程進入的時候,對象頭中的threadid為0,表示未偏向任何線程,也叫做匿名偏向量

public class SyncDemo1 {

   public static void main(String[] args) {
       SyncDemo1 syncDemo1 = new SyncDemo1();
       for (int i = 0; i < 100; i++) {
           syncDemo1.addString("test:" + i);
       }
   }

   private List list = new ArrayList<>();

   public synchronized void addString(String s) {
       list.add(s);
   }

}

當(dāng)?shù)谝粋€線程進入的時候發(fā)現(xiàn)是匿名偏向狀態(tài),則會用cas指令把mark words中的threadid替換為當(dāng)前線程的id如果替換成功,則證明成功拿到鎖,失敗則鎖膨脹;
當(dāng)線程第二次進入同步塊時,如果發(fā)現(xiàn)線程id和對象頭中的偏向線程id一致,則經(jīng)過一些比較之后,在當(dāng)前線程棧的lock record中添加一個空的Displaced Mark Word,由于操作的是私有線程棧,所以不需要cas操作,synchronized帶來的開銷基本可以忽略;
當(dāng)其他線程進入同步塊中時,發(fā)現(xiàn)偏向線程不是當(dāng)前線程,則進入到撤銷偏向鎖的邏輯,當(dāng)達到全局安全點時,鎖開始膨脹為輕量級鎖,原來的線程仍然持有鎖,如果發(fā)現(xiàn)偏向線程掛了,那么就把對象的頭改為無鎖狀態(tài),鎖膨脹

輕量鎖

當(dāng)鎖膨脹為輕量級鎖時,首先判斷是否有線程持有鎖(判斷mark work),如果是,則在當(dāng)前線程棧中創(chuàng)建一個lock record 復(fù)制mark word 并且cas的把當(dāng)前線程棧的lock record 的地址放到對象頭中,如果成功,則說明獲取到輕量級鎖,如果失敗,則說明鎖已經(jīng)被占用了,此時記錄線程的重入次數(shù)(把lock record 的mark word 設(shè)置為null),鎖會自旋可以進行自適應(yīng)性自旋,確保在競爭不激烈的情況下仍然可以不膨脹為重量級鎖從而減少消耗,如果cas失敗,則說明線程出現(xiàn)競爭,需要膨脹為重量級的鎖,代碼如下:

void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
  markOop mark = obj->mark();
  assert(!mark->has_bias_pattern(), "should not see bias pattern here");
  // 如果是無鎖狀態(tài)
  if (mark->is_neutral()) {
    //設(shè)置Displaced Mark Word并替換對象頭的mark word
    lock->set_displaced_header(mark);
    if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) {
      TEVENT (slow_enter: release stacklock) ;
      return ;
    }
  } else
  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");
    // 如果是重入,則設(shè)置Displaced Mark Word為null
    lock->set_displaced_header(NULL);
    return;
  }

  ...
  // 走到這一步說明已經(jīng)是存在多個線程競爭鎖了 需要膨脹為重量級鎖
  lock->set_displaced_header(markOopDesc::unused_mark());
  ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
}

重量鎖

重量級鎖就是我們傳統(tǒng)意義上的鎖了,當(dāng)線程發(fā)生競爭,鎖膨脹為重量級鎖,對象的mark word 指向堆中的 monitor,此時會將線程封裝為一個objectwaiter對象插入到monitor中的contextList中去,然后暫停當(dāng)前線程,當(dāng)持有鎖的線程釋放線程之前,會把contextList里面的所有線程對象插入到EntryList中去,會從EntryList中挑選一個線程喚醒,被選中的線程叫做Heir presumptive即假定繼承人(應(yīng)該是這樣翻譯),就是圖中的Ready Thread,假定繼承人被喚醒后會嘗試獲得鎖,但synchronized是非公平的,所以假定繼承人不一定能獲得鎖(這也是它叫"假定"繼承人的原因)。

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

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/74342.html

相關(guān)文章

  • 深入理解volatile類型——從Java虛擬機內(nèi)存模型角度

    摘要:本文從內(nèi)存模型角度,探討的實現(xiàn)原理。通過共享內(nèi)存或者消息通知這兩種方法,可以實現(xiàn)通信或同步?;诠蚕韮?nèi)存的線程通信是隱式的,線程同步是顯式的而基于消息通知的線程通信是顯式的,線程同步是隱式的。鎖規(guī)則鎖的解鎖,于于鎖的獲取或加鎖。 一、前言 在java多線程編程中,volatile可以用來定義輕量級的共享變量,它比synchronized的使用成本更低,因為它不會引起線程上下文的切換和調(diào)...

    mushang 評論0 收藏0
  • Java 虛擬機對鎖優(yōu)化所做的努力

    摘要:自選鎖鎖膨脹后,虛擬機為了避免線程真實地在操作系統(tǒng)層面掛起,虛擬機還會在做最后的努力自選鎖。 showImg(https://segmentfault.com/img/remote/1460000016159660?w=500&h=333); 作為一款公用平臺,JDK 本身也為并發(fā)程序的性能絞盡腦汁,在 JDK 內(nèi)部也想盡一切辦法提供并發(fā)時的系統(tǒng)吞吐量。這里,我將向大家簡單介紹幾種 J...

    ralap 評論0 收藏0
  • BATJ都愛問的多線程面試題

    摘要:今天給大家總結(jié)一下,面試中出鏡率很高的幾個多線程面試題,希望對大家學(xué)習(xí)和面試都能有所幫助。指令重排在單線程環(huán)境下不會出先問題,但是在多線程環(huán)境下會導(dǎo)致一個線程獲得還沒有初始化的實例。使用可以禁止的指令重排,保證在多線程環(huán)境下也能正常運行。 下面最近發(fā)的一些并發(fā)編程的文章匯總,通過閱讀這些文章大家再看大廠面試中的并發(fā)編程問題就沒有那么頭疼了。今天給大家總結(jié)一下,面試中出鏡率很高的幾個多線...

    高勝山 評論0 收藏0
  • 線程間的同步與通信(4)——Lock 和 Condtion

    摘要:為了拓展同步代碼塊中的監(jiān)視器鎖,開始,出現(xiàn)了接口,它實現(xiàn)了可定時可輪詢與可中斷的鎖獲取操作,公平隊列,以及非塊結(jié)構(gòu)的鎖。 前言 系列文章目錄 前面幾篇我們學(xué)習(xí)了synchronized同步代碼塊,了解了java的內(nèi)置鎖,并學(xué)習(xí)了監(jiān)視器鎖的wait/notify機制。在大多數(shù)情況下,內(nèi)置鎖都能很好的工作,但它在功能上存在一些局限性,例如無法實現(xiàn)非阻塞結(jié)構(gòu)的加鎖規(guī)則等。為了拓展同步代...

    Aceyclee 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<