这直接来自《Java 并发实践》。 以下原因会导致死锁:
class ThreadDeadlock {
ExecutorService exec = Executors.newSingleThreadExecutor();
public class RenderPageTask implements Callable<String> {
public String call() throws Exception {
Future<String> header, footer;
System.out.println(Thread.currentThread().getName());
header = exec.submit(new LoadFileTask("header.html"));
footer = exec.submit(new LoadFileTask("footer.html"));
//String page = renderBody();
// Will deadlock -- task waiting for result of subtask
//System.out.println("executed header and footer");
String headerS = header.get();
System.out.println("retrieved header");
String footerS = footer.get();
return headerS+ footerS;
}
}
}
class LoadFileTask implements Callable<String>{
String name;
public LoadFileTask(String name) {
super();
this.name = name;
}
@Override
public String call() throws Exception {
/*Scanner s = new Scanner(name);
StringBuilder str = new StringBuilder();
while(s.hasNextLine()){
str.append(s.nextLine());
}*/
System.out.println(Thread.currentThread().getName()+this.name);
return "";
}
}
/* Call from Main */
private static void checkDeadLock(){
ThreadDeadlock.RenderPageTask callable = new ThreadDeadlock().new RenderPageTask();
ExecutorService es = Executors.newFixedThreadPool(1);
es.submit(callable);
es.shutdown();
}
我无法弄清楚为什么这会导致僵局。 我检查过了,确实如此。它甚至返回 header.get() 并打印检索到的标头,那么它是如何死锁的?
代码中不存在死锁,JVM 不会关闭,因为它有工作线程 -
exec
服务的执行器线程(在 ThreadDeadlock
中定义)。
如果你添加
exec.shutdown();
在
return
中的RenderPageTask
之前,程序将在所有任务完成后终止。
死锁的原因很简单:第一个任务提交了另外 2 个任务并等待它们完成,有效地阻塞了执行器的单个工作线程并阻止任务执行。
要么:
永远不要在执行器下运行的任务中使用阻塞操作
或使用执行器根据需要添加工作线程
我对这样的例子产生了误解。 但正如 @ice 所说 - 您应该对页眉/页脚和 RenderPageTask 使用相同的执行器。 这是一个死锁的例子:
public static void main(String[] args) throws Exception {
var poolDeadlock = new ThreadDeadlock().new RenderPageTask();
System.out.println(poolDeadlock.call());
poolDeadlock.getExecutor().shutdown();
}
public static class ThreadDeadlock {
private final ExecutorService exec = Executors.newSingleThreadExecutor();
public class RenderPageTask implements Callable<String> {
public String call() throws Exception {
Future<String> header, footer;
header = exec.submit(new LoadFileTask("header.html"));
footer = exec.submit(new LoadFileTask("footer.html"));
String page = renderPage();
// Deadlock because you're using same single thread pool for header/footer
// and RenderPageTask
return header.get() + page + footer.get();
}
private String renderPage() throws Exception {
return exec.submit(new RenderPageTask()).get();
}
public ExecutorService getExecutor() {
return exec;
}
}
}
public static class LoadFileTask implements Callable<String> {
private final String data;
public LoadFileTask(String data) {
this.data = data;
}
@Override
public String call() {
return data;
}
}