4 回答
TA貢獻(xiàn)2021條經(jīng)驗(yàn) 獲得超8個(gè)贊
首先,沒(méi)有保證哪個(gè)線程首先啟動(dòng)。要獲得死鎖,一個(gè)線程必須鎖定lockA,然后第二個(gè)線程必須鎖定,lockB反之亦然。
public void processThis() {
lockA.lock();
// here the control should be switched to another thread
System.out.println("resource A -Thread1");
lockB.lock();
...
但是可能沒(méi)有足夠的時(shí)間在線程之間切換,因?yàn)槟挥袔仔写a。它太快了。為了模擬一些長(zhǎng)時(shí)間的工作,在兩種方法的第二個(gè)鎖定之前添加延遲
lockA.lock();
Thread.sleep(200); // 200 milis
然后第二個(gè)線程將能夠lockB在第一個(gè)釋放之前鎖定它們
TA貢獻(xiàn)1891條經(jīng)驗(yàn) 獲得超3個(gè)贊
您的代碼是死鎖的一個(gè)很好的例子,因?yàn)?ReenttrantLock 是一個(gè)互斥鎖,其行為與使用同步的隱式監(jiān)視器鎖訪問(wèn)相同。但是,由于這部分,您看不到死鎖:
private void execute() {
new Thread(this::processThis).start();
new Thread(this::processThat).start();
}
創(chuàng)建并啟動(dòng)第一個(gè)線程后,創(chuàng)建第二個(gè)線程需要一段時(shí)間。JVM 大約需要 50 us 甚至更少的時(shí)間來(lái)創(chuàng)建一個(gè)新線程,這聽(tīng)起來(lái)很短,但是對(duì)于完成第一個(gè)線程來(lái)說(shuō)已經(jīng)足夠了,因此不會(huì)發(fā)生死鎖。
我Thread.sleep();在您的代碼中添加了一個(gè),以便兩個(gè)線程可以以某種方式并行執(zhí)行。
package com.company;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DeadlockBasics {
private Lock lockA = new ReentrantLock();
private Lock lockB = new ReentrantLock();
public static void main(String[] args) {
DeadlockBasics dk = new DeadlockBasics();
dk.execute();
}
private void execute() {
new Thread(this::processThis).start();
new Thread(this::processThat).start();
}
// called by thread 1
private void processThis() {
lockA.lock();
// process resource A
try {
Thread.sleep(1000); //Wait for thread 2 to be executed
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 1 will own lock a");
lockB.lock();
// process resource B
System.out.println("Thread 1 will own lock b");
lockA.unlock();
lockB.unlock();
// Both locks will now released from thread 1
}
// called by thread 2
private void processThat() {
lockB.lock();
// process resource B
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 2 will own lock b");
lockA.lock();
// process resource A
System.out.println("Thread 2 will own lock a");
lockA.unlock();
lockB.unlock();
TA貢獻(xiàn)1876條經(jīng)驗(yàn) 獲得超6個(gè)贊
兩點(diǎn):
以與獲取鎖相反的順序釋放鎖。也就是說(shuō),
processThis應(yīng)該顛倒刪除鎖的順序。對(duì)于您的示例,順序無(wú)關(guān)緊要。但是,如果processThis在釋放 B 上的鎖之前嘗試在 A 上獲取新鎖,則可能會(huì)再次發(fā)生死鎖。更一般地,您會(huì)發(fā)現(xiàn)通過(guò)考慮鎖的范圍并避免重疊但非封閉的范圍來(lái)更容易考慮鎖。為了更好地突出這個(gè)問(wèn)題,我會(huì)
wait在每個(gè)線程中獲取第一個(gè)鎖之后調(diào)用,并execute啟動(dòng)兩個(gè)線程,然后在兩個(gè)線程上調(diào)用notify。
TA貢獻(xiàn)1842條經(jīng)驗(yàn) 獲得超13個(gè)贊
這確實(shí)可能導(dǎo)致死鎖,但并非總是如此,例如,如果 processThis() 完全執(zhí)行,然后 processThat() 或反之亦然,則沒(méi)有死鎖。您可以嘗試添加 Thread.delay(100) 或 Thread.yield() 來(lái)引導(dǎo)線程執(zhí)行走向死鎖,甚至解除對(duì)某個(gè)死鎖的解鎖。
添加回答
舉報(bào)
