问题
//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();
}
}
}
This code is take from Java concurrency in practice and as per the authors "ThreadStarvtionDeadlock" is happening here. Please help me finding how ThreadStarvationDeadlock is happening here and where? Thanks in advance.
回答1:
Deadlock & Starvation is occurring at following line:
return header.get() + page + footer.get();
HOW?
It will happen if we add some extra code to the program. It might be this one:
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();
}
Steps that leading to deadLock:
- Task is submitted to
exec
for Rendering the page viaCallable
implemented classRenderPageTask
. exec
started theRenderPageTask
in separateThread
, the onlyThread
that would execute other tasks submitted toexec
sequentially .- Inside
call()
method ofRenderPageTask
two more tasks are submitted toexec
. First isLoadFileTask("header.html")
and second isLoadFileTask("footer.html")
. But since the the ExecutorServiceexec
obtained via codeExecutors.newSingleThreadExecutor();
as mentioned here uses a single worker thread operating off an unbounded queueThread and the thread is already allocated to RenderPageTask , SoLoadFileTask("header.html")
andLoadFileTask("footer.html")
will be en queued to the unbounded queue waiting for there turn to be executed by thatThread
. RenderPageTask
is returning a String containing the concatenation of output ofLoadFileTask("header.html")
, body of page and output ofLoadFileTask("footer.html")
. Out of these three partspage
is obtained successfully byRenderPageTask
. But other two parts can only be obtained after both tasks are executed by the single Thread allocated byExecutorService
. And Thread will be free only aftercall()
method ofRenderPageTask
returns . Butcall
method ofRenderPageTask
will return only afterLoadFileTask("header.html")
andLoadFileTask("footer.html")
is returned. So Not lettingLoadFileTask
to execute is leading to Starvation . And each task waiting for other task for completion is leading to DeadLock
I hope this makes clear of why thread starvation deadlock is occurring in above code.
回答2:
The executor I see is a single thread executor and it gets two tasks to do. However these two tasks are not dependent on each other and they order of execution seems not important. Hence the return statement will only pause in Future.get calls as much as required to complete one and then another task.
It will be no deadlock in the code you show.
However I see one more task in the code (RenderPageTask), it is not clear which executor is actually running its code. If it is the same single thread executor, then deadlock is possible as the two submitted tasks cannot be processed before the main task returns (and this task can only return after the two tasks have been processed).
回答3:
The reason is not very obvious from the code itself but from the original book where the code is copied from: RenderPageTask submits two additional tasks to the Executor to fetch the page header and footer...
If the RenderPageTask were a task independent from the newSingleThreadExecutor, there would be no deadlock at all.
来源:https://stackoverflow.com/questions/14661036/is-thread-starvation-deadlock-happening-here-in-the-code