理解本文所需的知識程度:您已經完成了 Java 語法和 Java 核心任務,現在正在學習 Java 多執行緒。Java中的死鎖或死鎖是當執行緒對一對同步物件存在循環依賴時發生的錯誤。想像一下,一個執行緒進入物件監視器
在這種情況下,兩個線程都被阻塞,每個線程都在等待對方釋放鎖。但他們都不會這樣做,因為要做到這一點,他們需要完成他們的方法,並且它被另一個線程阻塞。所以他們被困在事情發生的地方
x
,另一個執行緒進入物件監視器y
。如果物件中的執行緒x
嘗試呼叫該物件上的任何同步方法y
,並且該物件y
同時嘗試呼叫該物件上的任何同步方法x
,則執行緒將陷入等待狀態。以下是 java 文件教學中關於死鎖這個概念的範例。這裡哪裡發生了線程阻塞?
public class Deadlock {
static class Friend {
private final String name;
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public synchronized void bow(Friend bower) {
System.out.format("%s: %s" + " has bowed to me!%n", this.name, bower.getName());
bower.bowBack(this);
}
public synchronized void bowBack(Friend bower) {
System.out.format("%s: %s"
+ " has bowed back to me!%n",
this.name, bower.getName());
}
}
public static void main(String[] args) {
final Friend alphonse =
new Friend("Alphonse");
final Friend gaston =
new Friend("Gaston");
new Thread(new Runnable() {
@Override
public void run() {
// System.out.println("Thread 1");
alphonse.bow(gaston);
// System.out.println("Th: gaston bowed to alphonse");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// System.out.println("Thread 2");
gaston.bow(alphonse);
// System.out.println("2.gaston waiting alph bowed");
}
}).start();
}
}
這裡有兩件重要的事情要理解:
- 每個並發運行的執行緒到底做什麼?
- 使用什麼鎖?
Friend
:alphonse
和gaston
。他們每個人都有自己的鎖。因此,這些鎖有兩種:舞男和加斯頓。當進入物件的同步方法時,它的鎖被鎖定,當退出該方法時,它被釋放(或解鎖)。現在關於線程。讓我們呼叫第一個線程Alphonse
(用大寫字母來區分它與物件 alphonse)。它的作用如下(我們稱之為A
,簡稱Alphonse
):
A: alphonse.bow(gaston) — получает лок alphonse;
A: gaston.bowBack(alphonse) — получает лок gaston;
A: возвращается из обоих методов, тем самым освобождая лок.
這是執行緒此時正在執行的操作Gaston
:
G: gaston.bow(alphonse) — получает лок gaston;
G: alphonse.bowBack(gaston) — получает лок alphonse;
G: возвращается из обоих методов, тем самым освобождая лок.
現在讓我們將這些數據放在一起並得出答案。線程可以以不同的順序交織在一起(即它們的事件將發生)。例如,如果順序如下:
A: alphonse.bow(gaston) — получает лок alphonse
G: gaston.bow(alphonse) — получает лок gaston
G: пытается вызвать alphonse.bowBack(gaston), но блокируется, ожидая лока alphonse
A: пытается вызвать gaston.bowBack(alphonse), но блокируется, ожидая лока gaston
deadlock
。然而,另一種編織也是可能的,其中一個線程將有時間在第二個線程開始之前完成:
A: alphonse.bow(gaston) — получает лок alphonse
A: gaston.bowBack(alphonse) — получает лок gaston
A: возвращается из обоих методов, открывая оба лока
G: gaston.bow(alphonse) — получает лок gaston
G: alphonse.bowBack(gaston) — получает лок alphonse
G: возвращается из обоих методов, открывая оба лока
在這種情況下,線程之間不存在相互阻塞。例如,添加了一些方法,允許另一個執行緒有時間執行。當結果取決於同時發生的事件的順序(計劃順序或執行速度)時,這樣的過程在俄語中稱為競爭條件 - “競爭條件”。並非所有競爭條件都可能導致死鎖,但是,根據我的經驗,只有競爭條件才會導致死鎖。 回答者: 戴夫·利勒森
還有什麼要讀的: |
---|
Java 開發者小組: |
GO TO FULL VERSION