在Java中,死鎖是多執行緒的一種情況,執行緒1等待執行緒2取得物件鎖,執行緒2等待執行緒1取得物件鎖。這裡,線程1和線程2都互相等待釋放鎖。 Java 中的多執行緒程式可能會導致死鎖,因為關鍵字synchronized 會在等待與所提到的物件連結的監視器或鎖定時阻塞執行緒。讓我們在以下部分中看到死鎖的工作原理和範例。
開始您的免費軟體開發課程
網頁開發、程式語言、軟體測試及其他
如所討論的,同步方法可以鎖定程式碼的特定部分。對於Java中的每個對象,都會有一個鎖,同步是一種鎖定函數或程式碼區塊的技術,以確保一次只有1個執行緒可以存取該函數或程式碼區塊。
當特定執行緒需要執行同步函數時,它首先嘗試取得鎖定。同時,如果另一個執行緒已經收到鎖,則第一個執行緒將等待,直到執行緒 2 釋放鎖。儘管同步可以防止資料不一致的問題,但仍存在同步問題。
假設有 2 個線程,「線程 1」和「線程 2」。執行緒 1 已取得物件 1 的鎖定,執行緒 2 已獲得物件 2 的鎖定。執行緒 1 執行方法 1,想要取得物件 2 的鎖定。但是,線程 2 已經獲得物件 2 的鎖定。
此外,執行緒2還需要取得物件1的鎖;但是,執行緒 1 擁有物件 1 上的鎖。此時,執行緒 1 和執行緒 2 這兩個執行緒都無法完成其執行,只能永遠等待該鎖定。這種情況稱為死鎖。
下面給出了提到的範例:
實作死鎖的Java程式。
代碼:
public class DeadLockExample { //main method public static void main(String[] args) throws InterruptedException { //create three objects 1, 2 and 3 Object o1 = new Object(); Object o2 = new Object(); Object o3 = new Object(); //create three threads 1, 2 and 3 Thread th1 = new Thread(new SynchronizationThread(o1, o2), "thread 1"); Thread th2 = new Thread(new SynchronizationThread(o2, o3), "thread 2"); Thread th3 = new Thread(new SynchronizationThread(o3, o1), "thread 3"); //start thread 1 th1.start(); //thread sleeps for 5000 seconds Thread.sleep(5000); //start thread 2 th2.start(); //thread sleeps for 5000 seconds Thread.sleep(5000); //start thread 3 th3.start(); } } class SynchronizationThread implements Runnable { private Object o1; private Object o2; public SynchronizationThread(Object o1, Object o2){ this.o1=o1; this.o2=o2; } //function run @Override public void run() { //store the name of the thread String nm = Thread.currentThread().getName(); System.out.println( nm + " attaining lock on "+ o1 ) ; synchronized (o1) { System.out.println( nm + " attained lock on "+ o1 ) ; work(); System.out.println( nm + " attaining lock on "+ o2 ) ; synchronized (o2) { System.out.println( nm + " attained lock on "+ o2 ); work(); } System.out.println( nm + " released lock on "+ o2 ) ; } System.out.println( nm + " released lock on "+ o1 ) ; System.out.println( nm + " completed execution.") ; } //function work private void work() { try { //thread sleeps Thread.sleep(30000); } //catch the exception catch (InterruptedException exc) { exc.printStackTrace(); } } }
輸出:
在這個程式中,3個正在運行的執行緒共享一個資源,並且它們以獲取物件1上的鎖的方式運行,但是當它嘗試獲取物件2上的鎖時,它會進入等待狀態。為了防止死鎖,可以將程式碼重寫如下。
代碼:
public class DeadLockExample { public static void main(String[] args) throws InterruptedException { Object o1 = new Object(); Object o2 = new Object(); Object o3 = new Object(); Thread th1 = new Thread(new SynchronizationThread(o1, o2), "thread 1"); Thread th2 = new Thread(new SynchronizationThread(o2, o3), "thread 2"); Thread th3 = new Thread(new SynchronizationThread(o3, o1), "thread 3"); //start thread 1, 2 and 3 th1.start(); //thread sleeps for 5000 seconds Thread.sleep(5000); th2.start(); //thread sleeps for 5000 seconds Thread.sleep(5000); th3.start(); } } class SynchronizationThread implements Runnable{ private Object o1; private Object o2; public SynchronizationThread(Object o1, Object o2){ this.o1=o1; this.o2=o2; } //function run @Override public void run() { //store the name of the thread String nm = Thread.currentThread().getName(); System.out.println( nm + " attaining lock on "+ o1 ) ; synchronized (o1) { System.out.println( nm + " attained lock on "+ o1 ) ; work(); } System.out.println( nm + " released lock on "+ o1 ) ; System.out.println( nm + " acquiring lock on " + o2 ); synchronized (o2) { System.out.println( nm + " attained lock on "+ o2 ); work(); } System.out.println( nm + " released lock on "+ o2 ) ; System.out.println( nm + " released lock on "+ o1 ) ; System.out.println( nm + " completed execution.") ; } //function work private void work() { try { //thread sleeps Thread.sleep(30000); } //catch the exception catch (InterruptedException exc) { exc.printStackTrace(); } } }
輸出:
以下是有助於避免死鎖情況的指南。
巢狀鎖是導致死鎖的常見原因之一。如果另一資源已持有一個資源,請勿鎖定該資源以避免死鎖。如果使用者只使用 1 個對象,則不可能導致死鎖。
人們建議僅鎖定必要的資源。但是,即使不需要,某些使用者也可能會嘗試鎖定資源。
如果兩個執行緒借助執行緒連線無限期地等待對方完成,就會發生死鎖。如果執行緒需要等待其他執行緒完成,最好使用具有等待執行緒完成的最大時間的 join。
以上是Java 中的死鎖的詳細內容。更多資訊請關注PHP中文網其他相關文章!