一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java并發之嵌套管程鎖死詳解

Java并發之嵌套管程鎖死詳解

2021-01-31 16:48六尺帳篷 Java教程

這篇文章主要介紹了Java并發之嵌套管程鎖死詳解,涉及嵌套管程鎖死的發生,實例等相關內容,具有一定參考價值,需要的朋友可以了解下。

·嵌套管程死鎖是如何發生的
·具體的嵌套管程死鎖的例子
·嵌套管程死鎖 vs 死鎖

嵌套管程鎖死類似于死鎖, 下面是一個嵌套管程鎖死的場景:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Thread 1 synchronizes on A
Thread 1 synchronizes on B (while synchronized on A)
Thread 1 decides to wait for a signal from another thread before continuing
Thread 1 calls B.wait() thereby releasing the lock on B, but not A.
 
Thread 2 needs to lock both A and B (in that sequence)
    to send Thread 1 the signal.
Thread 2 cannot lock A, since Thread 1 still holds the lock on A.
Thread 2 remain blocked indefinately waiting for Thread1
    to release the lock on A
 
Thread 1 remain blocked indefinately waiting for the signal from
    Thread 2, thereby
    never releasing the lock on A, that must be released to make
    it possible for Thread 2 to send the signal to Thread 1, etc.

線程1獲得A對象的鎖。
線程1獲得對象B的鎖(同時持有對象A的鎖)。
線程1決定等待另一個線程的信號再繼續。
線程1調用B.wait(),從而釋放了B對象上的鎖,但仍然持有對象A的鎖。

線程2需要同時持有對象A和對象B的鎖,才能向線程1發信號。
線程2無法獲得對象A上的鎖,因為對象A上的鎖當前正被線程1持有。
線程2一直被阻塞,等待線程1釋放對象A上的鎖。

線程1一直阻塞,等待線程2的信號,因此,不會釋放對象A上的鎖,
而線程2需要對象A上的鎖才能給線程1發信號……

我們看下面這個實際的例子:

java" id="highlighter_922014">
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//lock implementation with nested monitor lockout problem
public class Lock{
 protected MonitorObject monitorObject = new MonitorObject();
 protected boolean isLocked = false;
 public void lock() throws InterruptedException{
  synchronized(this){
   while(isLocked){
    synchronized(this.monitorObject){
      this.monitorObject.wait();
    }
   }
   isLocked = true;
  }
 }
 public void unlock(){
  synchronized(this){
   this.isLocked = false;
   synchronized(this.monitorObject){
    this.monitorObject.notify();
   }
  }
 }
}

可以看到,lock()方法首先在”this”上同步,然后在monitorObject上同步。如果isLocked等于false,因為線程不會繼續調用monitorObject.wait(),那么一切都沒有問題 。但是如果isLocked等于true,調用lock()方法的線程會在monitorObject.wait()上阻塞。

這里的問題在于,調用monitorObject.wait()方法只釋放了monitorObject上的管程對象,而與”this“關聯的管程對象并沒有釋放。換句話說,這個剛被阻塞的線程仍然持有”this”上的鎖。

(校對注:如果一個線程持有這種Lock的時候另一個線程執行了lock操作)當一個已經持有這種Lock的線程想調用unlock(),就會在unlock()方法進入synchronized(this)塊時阻塞。這會一直阻塞到在lock()方法中等待的線程離開synchronized(this)塊。但是,在unlock中isLocked變為false,monitorObject.notify()被執行之后,lock()中等待的線程才會離開synchronized(this)塊。

簡而言之,在lock方法中等待的線程需要其它線程成功調用unlock方法來退出lock方法,但是,在lock()方法離開外層同步塊之前,沒有線程能成功執行unlock()。

結果就是,任何調用lock方法或unlock方法的線程都會一直阻塞。這就是嵌套管程鎖死。

具體的嵌套管程死鎖的例子

例如,如果你準備實現一個公平鎖。你可能希望每個線程在它們各自的QueueObject上調用wait(),這樣就可以每次喚醒一個線程。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//Fair Lock implementation with nested monitor lockout problem
public class FairLock {
 private boolean      isLocked    = false;
 private Thread      lockingThread = null;
 private List<QueueObject> waitingThreads =
      new ArrayList<QueueObject>();
 public void lock() throws InterruptedException{
  QueueObject queueObject = new QueueObject();
  synchronized(this){
   waitingThreads.add(queueObject);
   while(isLocked || waitingThreads.get(0) != queueObject){
    synchronized(queueObject){
     try{
      queueObject.wait();
     }catch(InterruptedException e){
      waitingThreads.remove(queueObject);
      throw e;
     }
    }
   }
   waitingThreads.remove(queueObject);
   isLocked = true;
   lockingThread = Thread.currentThread();
  }
 }
 public synchronized void unlock(){
  if(this.lockingThread != Thread.currentThread()){
   throw new IllegalMonitorStateException(
    "Calling thread has not locked this lock");
  }
  isLocked   = false;
  lockingThread = null;
  if(waitingThreads.size() > 0){
   QueueObject queueObject = waitingThread.get(0);
   synchronized(queueObject){
    queueObject.notify();
   }
  }
 }
}

乍看之下,嗯,很好,但是請注意lock方法是怎么調用queueObject.wait()的,在方法內部有兩個synchronized塊,一個鎖定this,一個嵌在上一個synchronized塊內部,它鎖定的是局部變量queueObject。

當一個線程調用queueObject.wait()方法的時候,它僅僅釋放的是在queueObject對象實例的鎖,并沒有釋放”this”上面的鎖。
現在我們還有一個地方需要特別注意, unlock方法被聲明成了synchronized,這就相當于一個synchronized(this)塊。這就意味著,如果一個線程在lock()中等待,該線程將持有與this關聯的管程對象。所有調用unlock()的線程將會一直保持阻塞,等待著前面那個已經獲得this鎖的線程釋放this鎖,但這永遠也發生不了,因為只有某個線程成功地給lock()中等待的線程發送了信號,this上的鎖才會釋放,但只有執行unlock()方法才會發送這個信號。

因此,上面的公平鎖的實現會導致嵌套管程鎖死。

Nested Monitor Lockout vs. Deadlock

嵌套管程鎖死與死鎖很像:都是線程最后被一直阻塞著互相等待。

但是兩者又不完全相同。在死鎖中我們已經對死鎖有了個大概的解釋,死鎖通常是因為兩個線程獲取鎖的順序不一致造成的,線程1鎖住A,等待獲取B,線程2已經獲取了B,再等待獲取A。如死鎖避免中所說的,死鎖可以通過總是以相同的順序獲取鎖來避免。但是發生嵌套管程鎖死時鎖獲取的順序是一致的。線程1獲得A和B,然后釋放B,等待線程2的信號。線程2需要同時獲得A和B,才能向線程1發送信號。所以,一個線程在等待喚醒,另一個線程在等待想要的鎖被釋放。

不同點歸納如下:

?
1
2
3
4
In deadlock, two threads are waiting for each other to release locks.
In nested monitor lockout, Thread 1 is holding a lock A, and waits
for a signal from Thread 2. Thread 2 needs the lock A to send the
signal to Thread 1.

死鎖中,二個線程都在等待對方釋放鎖。

嵌套管程鎖死中,線程1持有鎖A,同時等待從線程2發來的信號,線程2需要鎖A來發信號給線程1。

總結

以上就是本文關于Java并發之嵌套管程鎖死詳解的全部內容,希望對大家有所幫助。有什么問題可以隨時留言,小編會及時回復大家的。感謝朋友們對本站的支持!

原文鏈接:http://www.jianshu.com/p/004468aa41ba

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日韩毛片在线视频 | 美女扒开胸罩露出胸大乳 | 狠狠综合久久综合网站 | 国产成人盗摄精品 | 久久国产综合精品欧美 | 欧美男同猛男 videos 同性 | 99在线视频精品 | 国产v在线在线观看羞羞答答 | 国产一级网站 | 亚洲va在线va天堂va偷拍 | 欧美视频精品一区二区三区 | 亚洲国产精品嫩草影院久久 | 四虎网站入口 | 希岛爱理aⅴ在线中文字幕 午夜综合网 | 亚洲六月丁香六月婷婷色伊人 | 息与子中文字幕完整在线 | 色综合久久综精品 | 免费yjsp妖精com | 97久久久亚洲综合久久88 | 日b视频免费看 | 饭冈加奈子在线播放观看 | xxx美国| 香港三级系列在线播放 | 天天性综合| 日本中文字幕一区二区有码在线 | 亚洲天堂h| 国内自拍视频在线观看 | 亚洲国产在线观看免费视频 | 欧美同性猛男野外gay免费 | 175m美女被网友灌醉啪啪玩脚 | 香蕉久久久久久狠狠色 | 精品综合久久久久久8888 | 精品国产一区二区三区久久影院 | 日韩欧美一级大片 | 亚洲高清中文字幕一区二区三区 | 国产玖玖在线观看 | 性xxxx中国| 2019天天干天天操 | 免费观看在线观看 | 视频一区国产精戏刘婷30 | 美女和男人免费网站视频 |