Java - 從例子中看如何解決死結(Dead lock)?

死結(Dead lock)定義:各執行緒間資源彼此交互取用,有機率造成「死結」(Dead lock)。

我們從例子中初步認識如何防止死結。

防止Dead lock例子:

package my11Test;

/**
 *
 * @author lucrecialin
 */

import java.util.concurrent.locks.*;

class Testing {
    private ReentrantLock lock = new ReentrantLock();
    private String name;
    
    Testing(String name) {
        this.name = name;
    }
    void doPrint(Testing test) {
        System.out.printf("%s 和 %s 都有成功鎖定了。%n", this.name, test.name);
    }
    void doIt(Testing test) {
        while (true) {
            try {
                if (lockAll(test)) {
                    doPrint(test);
                    break;
                }
            } finally {
                unLockAll(test);
            }
        }
    }
    
    private boolean lockAll(Testing test) {
        return this.lock.tryLock() && test.lock.tryLock();
    }
    
    private void unLockAll(Testing test) {
        if (this.lock.isHeldByCurrentThread()) {
            this.lock.unlock();
        }
        if (test.lock.isHeldByCurrentThread()) {
            test.lock.unlock();
        } 
    }
}

public class SolveDeadLock {
    public static void main(String[] args) {
        Testing test1 = new Testing("Testing1");
        Testing test2 = new Testing("Testing2");
        
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                test1.doIt(test2);
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                test2.doIt(test1);
            }
        });
        
        thread1.start();
        thread2.start();
    }
}

死結原因:
test1物件呼叫doIt()時會鎖定test1物件,但因doIt()中嘗試呼叫test2物件的doPrint(),有機率無法取得該鎖定(如果test2物件也正呼叫doIt()時會鎖定test2物件),造成死結,反之亦然。

解法:

因為doIt()要成功執行完,需要test1test2物件的鎖定,因而「確認兩物件皆成功鎖定後再執行程式」。


下面為編譯結果:


留言

熱門文章