1. 程式人生 > >多執行緒死鎖經典案例,必定會發生死鎖

多執行緒死鎖經典案例,必定會發生死鎖

        Java執行緒死鎖是一個經典的多執行緒問題,因為不同的執行緒都在等待根本不可能被釋放的鎖,從而導致所有的任務都無法繼續完成。換言之只要互相等待對方釋放鎖就有可能出現死鎖。下面將用一個簡單的例子加以說明,如有問題,請多多指教。

        某日AB兩位壯士各獲一張一模一樣的藏寶圖,他們相距甚遠,互不認識。兩位壯士不僅武藝雙全,還富有謀略,細讀藏寶圖,壯士得知寶藏就在某處,但是需要兩把鑰匙才能開啟,而這兩把鑰匙分別存在了某處,恰巧壯士A離鑰匙1更近,壯士B離鑰匙2更近,於是他們採用就近原則開啟尋寶之路。A先找到了鑰匙1,為了安全起見,A把鑰匙收入囊中,這時B也找到了鑰匙2,為了安全起見,B也把鑰匙收入囊中。他們各自開始尋找第二把鑰匙,但是到達他們原定的目的地之後並沒有找到鑰匙(其實都被對方據為己有了),但是心有不甘,心想這絕不能半途而廢,他們就這樣一直在苦苦等待尋找著......

        上面就是多執行緒死鎖的經典案例,兩個人可看作是兩個不同的執行緒,A獲得了一把鎖a想嘗試獲取另外一把鎖b,B獲取了一把鎖b想嘗試獲取另外一把鎖a,他們互相持有對方想要的鎖,在沒有獲取到對方的鎖之前,是不會將自己的鎖給放棄的,這樣雙方永遠也無法集齊兩把鎖,於是發生了死鎖。

        下面用程式碼來實現上面的場景:

public class DeathlyLockService {

	//鑰匙一
	private Object lock1 = new Object();
	//鑰匙二
	private Object lock2 = new Object();
	
	//開啟寶藏之方法,線路不同,先後獲取到的鑰匙也不同
	public void openTreasure() throws Exception{
		//線路一
		if(Thread.currentThread().getName().equals("大AAA")){
			//先獲取的是鑰匙一
			synchronized (lock1) {
				System.out.println("執行緒"+Thread.currentThread().getName()+"拿到了lock1");
				//成功獲取到一枚鑰匙,繼續尋找
				Thread.sleep(2000);
				//嘗試獲取第二把鑰匙
				synchronized(lock2){
					//成功獲取到第二把鑰匙
					System.out.println("執行緒"+Thread.currentThread().getName()+"拿到了lock2");
					Thread.sleep(2000);
					//開啟了寶藏
					System.out.println("執行緒"+Thread.currentThread().getName()+"集齊了兩把鑰匙開寶藏成功");
				}
			}
		}
		//線路二
		if(Thread.currentThread().getName().equals("小BBB")){
			//先獲取鑰匙二
			synchronized (lock2) {
				System.out.println("執行緒"+Thread.currentThread().getName()+"拿到了lock2");
				//成功獲取到一枚鑰匙,繼續尋找
				Thread.sleep(2000);
				//嘗試獲取第二把鑰匙
				synchronized(lock1){
					//成功獲取到第二把鑰匙
					System.out.println("執行緒"+Thread.currentThread().getName()+"拿到了lock1");
					Thread.sleep(2000);
					//開啟了寶藏
					System.out.println("執行緒"+Thread.currentThread().getName()+"集齊了兩把鑰匙開寶藏成功");
				}
			}
		}
	}
}
//自定義執行緒
public class MyThread extends Thread{

	private DeathlyLockService deathlyLockService;
	
	public MyThread(DeathlyLockService deathlyLockService){
		this.deathlyLockService=deathlyLockService;
	}
	
	@Override
	public void run(){
		try {
			System.out.println("執行緒"+Thread.currentThread().getName()+"開始執行");
			deathlyLockService.openTreasure();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

        main方法測試:

//互相持有對方的鎖,比如A物件進行操作時,需要B物件釋放鎖,此時B物件正在操作,需要A物件釋放鎖
		DeathlyLockService s = new DeathlyLockService();
		Thread a = new MyThread(s);
		a.setName("大AAA");
		a.start();
		Thread b = new MyThread(s);
		b.setName("小BBB");
		b.start();

列印結果永遠卡在:

        執行緒小BBB開始執行
        執行緒大AAA開始執行
        執行緒小BBB拿到了lock2

        執行緒大AAA拿到了lock1

        。。。。。。

結論:因為發生了死鎖,他們倆永遠無法獲取寶藏。知道了怎樣會發生死鎖,就知道如何避免這種情況的發生,希望大家以後都能開心的尋寶。