線程飢餓死鎖

/**
 * 線程飢餓死鎖——在單線程Executor中發生死鎖
 */
public class ThreaDeadLock {
        //單線程Executor
	ExecutorService exec = Executors.newSingleThreadExecutor();
	
	class RenderPageTask implements Callable<String>{

		@Override
		public String call() throws Exception {
			Future<String> header,footer;
			header = exec.submit(new Callable<String>(){
				@Override
				public String call() throws Exception {
					System.out.println("---渲染頭部---");
					Thread.sleep(200);
					return "頁頭";
				}
				
			});
			footer = exec.submit(new Callable<String>(){

				@Override
				public String call() throws Exception {
					System.out.println("---渲染頁腳---");
					Thread.sleep(200);
					return null;
				}
				
			});
			String page = renderBody();
			return header.get()+page+footer.get();
		}

		private String renderBody() throws InterruptedException {
			System.out.println("---渲染Body---");
			Thread.sleep(200);
			return null;
		}
		
	}
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ThreaDeadLock d = new ThreaDeadLock();
		Future<String> result = d.exec.submit(d.new RenderPageTask());
		System.out.println("---結果:---"+result.get());
	}
}

運行結果:可以看到當提交了依賴性任務“渲染頁頭”以及“渲染頁尾”後發生了死鎖

原因:在RenderPageTask中有兩個子任務footer和header,當在main函數中提交RenderPageTask任務到線程池時,實際上提交了3個任務,但由於線程池是單線程的Executor,每次只會執行一個任務,而RenderPageTask會阻塞等待兩個子任務的結果返回,但兩個子任務得不到線程來運行,就會阻塞,所以就會產生死鎖。

小結:在上面代碼中由於使用單線程的Executor,所以會經常發生死鎖。同樣,如果線程池不夠大,那麼當多個任務通過柵欄機制來彼此協調時,將導致線程飢餓死鎖。(摘自Java併發編程實戰第8章)

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