Java基礎(33)——多線程相關知識詳解及示例分析五(線程死鎖)

Java基礎(33)——多線程相關知識詳解及示例分析五(線程死鎖)


版權聲明

  • 本文原創作者:清風不渡
  • 博客地址:https://blog.csdn.net/WXKKang

  上面我們講到了Java中線程互斥的機制,那就是給線程訪問的數據上鎖,那麼這樣就一定安全嗎?答案肯定是否定的,這個世界上沒有絕對安全的東西,而上篇所講到的方法就會出現線程死鎖的現象,那麼這個現象是什麼意思呢?我們該怎樣處理或者說怎樣避免發生這樣的現象呢?下面我們就來一一學習吧

一、線程死鎖

  多線程中使用鎖會造成效率低,如果出現了同步嵌套,就容易產生死鎖問題
  死鎖是指兩個或者兩個以上的線程在執行的過程中,因爭奪資源產生的一種互相等待現象
  如果兩個線程之間有多個共享對象,如果兩個線程分別持有對方所需要的共享對象的鎖,在試圖獲取對方線程所持有的共享對象的鎖時,就有死鎖的危險

1、死鎖產生的原因

  加入我們現在有兩個線程(線程1與線程2),這兩個線程之間有兩個共享對象(對象A和對象B),在線程執行的過程中,線程1與線程2都必須同時獲得對象A與對象B後才能正常工作
  那麼當線程1獲得了對象A的鎖、線程2獲得了對象B的鎖,如果兩個線程都不釋放所獲得的對象的鎖,那麼線程1將不能得到對象B的鎖,線程2將不能得到對象A的鎖,這種情況下兩個線程都將被阻塞,即所謂的死鎖
在這裏插入圖片描述

2、死鎖的解決方案

  死鎖通常是由於資源的無序使用,導致線程不能得到正常執行所需要的資源
  解決死鎖問題的方法,就是所有線程使用一致的順序申請資源鎖。例如:
  1、線程1和線程2都是按照對象A、對象B的順序來獲得對象鎖
  2、將對象A編號爲1,對象B編號爲2,線程1和線程2都必須先獲得1號資源後方可再獲取2號資源

3、死鎖示例

  下面我們來演示一個發生死鎖的例子,這裏有四個對象:藝術家、畫匠、筆、紙。藝術家、畫匠在工作時都需要同時有筆、紙  死鎖演示效果:
  1、藝術家首先得到筆,然後再去獲取紙;工匠首先得到紙,然後再去獲取筆
  2、由於藝術家和工匠都不願意放棄自己獲得的筆、紙,因此二者都不能同時獲得筆和紙,因此都無法工作

  代碼如下:

package qfbd.com;
/*
原創作者:清風不渡
博客地址:https://blog.csdn.net/WXKKang
*/
public class Demo {

	public static void main(String[] args) throws Exception {
		Resource resource = new Resource();
		
		//創建藝術家對象
		Artist artist = new Artist();
		artist.prepace(resource);
		
		//創建工匠
		Limner limner = new Limner();
		limner.prepace(resource);
		
		//這裏一定要先啓動藝術家纔能有死鎖情況
		artist.start();
		limner.start();
	}
}

//筆類
class Pen{
	
}
//紙類
class Paper{
	
}
//共享的資源類,這裏同時有筆和紙
class Resource{
	private Pen pen = new Pen();
	private Paper paper = new Paper();
	
	public Paper getPaper(){
		return paper;
	}
	
	public Pen getPen(){
		return pen;
	}
}

/*
 * 藝術家
 * 
 * 這是一個線程類,在線程體中有兩個同步塊,分別是對pen和paper對象進行同步
 */
class Artist extends Thread {
	private Resource resource;
	
	@Override
	public void run() {
		Pen pen = resource.getPen();
		System.out.println("藝術家獲得筆!!!");
		
		synchronized (pen) {
			/*
			 * 加入睡眠原因:
			 * 1、在運行線程時,藝術家線程先執行,他首先獲得筆
			 * 2、如果沒有這個睡眠,那麼可能畫匠還沒來的及獲取到紙,
			 * 	    藝術家線程就獲取到了紙,這樣就無法測試死鎖的情形了
			 */
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				System.out.println("藝術家睡眠發生異常!!!");
			}
			//睡眠之後獲取紙,但預測紙已經被畫匠獲取到了,此刻進入等待
			Paper paper = resource.getPaper();
			synchronized (paper) {
				System.out.println("藝術家可以畫畫了!!");
			}
			
		}
	}
	
	public void prepace(Resource resource){
		this.resource = resource;
	}
}

/*
 * 畫匠
 * 
 * 這是一個線程類,在線程體中有兩個同步塊,分別是對paper和pen對象進行同步
 * 注意:他的同步對象paper和pen的順序和藝術家是相反的
 */
class Limner extends Thread{
	private Resource resource;
	
	@Override
	public void run() {
		Paper paper = resource.getPaper();
		System.out.println("畫匠得到紙!!!");
		synchronized (paper) {
			//然後獲取筆,預測被藝術家得到並睡眠,此刻進入等待
			Pen pen = resource.getPen();
			synchronized (pen) {
				System.out.println("畫匠可以畫畫了!!!");
			}
		}
	}
	public void prepace(Resource resource){
		this.resource = resource;
	}
	
}

  執行結果如下:
在這裏插入圖片描述
  可以發現,程序運行“卡死了”,即發生了所謂的死鎖現象

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章