/**
* 線程飢餓死鎖——在單線程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章)