//code taken from java concurrency in practice
package net.jcip.examples;
import java.util.concurrent.*;
public class ThreadDeadlock
{
ExecutorService exec = Executors.newSingleThreadExecutor();
public class LoadFileTask implements Callable<String> {
private final String fileName;
public LoadFileTask(String fileName) {
this.fileName = fileName;
}
public String call() throws Exception {
// Here's where we would actually read the file
return "";
}
}
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 = renderBody();
// Will deadlock -- task waiting for result of subtask
return header.get() + page + footer.get();
}
}
}
此代码在实践中取自Java并发,并且根据作者“ThreadStarvtionDeadlock”在这里发生。请帮我看看ThreadStarvationDeadlock是如何在这里发生的?提前谢谢。
答案 0 :(得分:12)
死锁&amp;饥饿发生在以下几行:
return header.get() + page + footer.get();
如何吗
如果我们在程序中添加一些额外的代码就会发生。可能就是这个:
public void startThreadDeadlock() throws Exception
{
Future <String> wholePage = exec.submit(new RenderPageTask());
System.out.println("Content of whole page is " + wholePage.get());
}
public static void main(String[] st)throws Exception
{
ThreadDeadLock tdl = new ThreadDeadLock();
tdl.startThreadDeadLock();
}
导致deadLock的步骤:
exec
,以便通过Callable
已实施的课程RenderPageTask
呈现该网页。exec
在单独的RenderPageTask
中启动了Thread
,Thread
是执行其他任务的exec
,后续执行call()
。RenderPageTask
内exec
方法,另外两个任务提交给LoadFileTask("header.html")
。首先是LoadFileTask("footer.html")
,第二个是exec
。但是由于提到的Executors.newSingleThreadExecutor();
通过代码LoadFileTask("header.html")
获得的here 使用单个工作线程操作无限制的queueThread ,并且该线程已经分配给RenderPageTask ,因此LoadFileTask("footer.html")
和Thread
将排队到无限队列,等待由RenderPageTask
执行。LoadFileTask("header.html")
返回一个字符串,其中包含LoadFileTask("footer.html")
的输出,页面主体和page
输出的串联。 RenderPageTask
成功获得了这三个部分ExecutorService
。但是,只有在call()
分配的单个线程执行这两个任务后才能获得其他两个部分。只有在RenderPageTask
call
方法返回后,线程才会免费。但RenderPageTask
的{{1}}方法只会在LoadFileTask("header.html")
和LoadFileTask("footer.html")
返回后返回。所以不要让LoadFileTask
执行导致饥饿。等待完成其他任务的每个任务都会导致 DeadLock
答案 1 :(得分:0)
我看到的执行程序是一个单线程执行程序,它有两个任务要做。然而,这两个任务并不依赖于彼此,并且它们的执行顺序似乎并不重要。因此,return语句只会在Future.get次调用中暂停,以完成一个然后完成另一个任务。
您显示的代码不会出现死锁。
然而我在代码中看到了另外一个任务(RenderPageTask),不清楚哪个执行器实际运行其代码。如果它是相同的单线程执行程序,则死锁是可能的,因为在主任务返回之前无法处理两个提交的任务(并且此任务只能在处理完两个任务后返回)。
答案 2 :(得分:0)
原因不是很明显来自代码本身,而是来自复制代码的原始书:RenderPageTask向Executor提交两个附加任务以获取页眉和页脚...
如果RenderPageTask是独立于newSingleThreadExecutor的任务,则根本不存在死锁。