簡體   English   中英

為什么這個代碼在運行時永遠不會死鎖?

[英]Why this code never deadlocks when I run it?

我正在嘗試Java多線程中的死鎖概念。 我遇到了一個可能導致死鎖的代碼片段:

public class Deadlock {
double amount = 10.0;

public double deposit(double d) {
    amount += d;
    return amount;
}

public double withdraw(double d) {
    amount -= d;
    return amount;
}

public static void transfer(Deadlock from, Deadlock to,double d) {
    synchronized(from) {
        synchronized(to) {
            from.withdraw(d);
            try {
                System.out.println(Thread.currentThread().getName());
                Thread.sleep(5000);
            }catch(Exception e){}

            to.deposit(d);
            System.out.println("Done");
        }
    }
}

public static void main(String[] args) {
    final Deadlock a = new Deadlock();
    final Deadlock b = new Deadlock();

    Thread t1 = new Thread(new Runnable() {
        public void run() {
            transfer(a, b, 10.0);
        }
    });
    t1.start();



    Thread t2 = new Thread(new Runnable() {
        public void run() {
            transfer(b, a, 10.0);
        }
    });
    t2.start();
}
}

基本上,代碼嘗試同時獲取對象a和b上的鎖。 但是,當我運行它時,代碼總是成功完成。 為什么不會出現這種僵局?

如果一個線程能夠同時到達這兩個線程,則只需要線程調度程序

synchronized(from) {
    synchronized(to) {

在另一個線程到達第一個之前。 在這些之間增加足夠的sleep

synchronized (from) {
    try {
        Thread.sleep(20L);
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }
    synchronized (to) {

你應該遇到僵局。

為了使出現僵局,就需要有類似以下情形發生:

t1 acquires lock a
t2 acquires lock b

t1 attempts to acquire lock b
t2 attempts to acquire lock a

你能逼這個嗎? 您可以嘗試在鎖定獲取之間移動睡眠語句,但這一切都必須在不受您直接控制的窗口內發生。

嘗試這個:

public static void transfer(DeadLock from, DeadLock to,double d) {
    synchronized(from) {
        try {
            System.out.println(Thread.currentThread().getName() +" acquires lock " +from);
            Thread.sleep(5000);
            synchronized(to) {
                System.out.println(Thread.currentThread().getName() +" acquires lock " +to);
                from.withdraw(d);
                to.deposit(d);
                System.out.println("Done");
            }
        }catch(Exception e){}
    }
}

並確認您處於死鎖狀態,將SIGQUIT信號發送到您的Java進程 - JVM將報告線程陷入僵局

到達方法傳輸的第一個線程將獲得兩個資源(往返),以便它可能不會與第二個線程交錯。 話雖如此,這段代碼仍然容易陷入僵局。 下面的代碼嘗試僅獲取第一個鎖,其長度足以使第二個線程計划運行:

public static void transfer(Deadlock from, Deadlock to, double d) throws InterruptedException {
    synchronized (from) {
        Thread.sleep(5000);
        synchronized (to) {
            from.withdraw(d);
            System.out.println(Thread.currentThread().getName());
            to.deposit(d);
            System.out.println("Done");
        }
    }
}

sleeping a Thread does not release the locks it holds, while waiting releases the lock

T1具有對兩個死鎖對象的鎖定,即使在休眠期間也是如此,並且只有當T1存在相應的同步鎖時,t2才能訪問它。

因此,為了引入死鎖,您需要在sychronized語句之間休眠。

另外,您可以嘗試代替Thread.sleep(5000); to.wait(5000);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM