//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在这里和哪里发生的情况吗?提前致谢。

最佳答案

死锁和饥饿发生在以下行:

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();
    }

导致死锁的步骤:
  • 任务已提交给exec,以通过Callable实现的类RenderPageTask呈现页面。
  • exec在单独的RenderPageTask中启动了Thread,这是唯一的Thread,它将执行依次提交给exec的其他任务。
  • call()RenderPageTask方法内部,还有两个任务提交给exec。第一个是LoadFileTask("header.html"),第二个是LoadFileTask("footer.html")。但是由于如上所述通过代码exec获得的ExecutorService Executors.newSingleThreadExecutor(); here 使用单个工作线程在不受限制的queueThread 上操作,并且该线程已经分配给RenderPageTask,因此LoadFileTask("header.html")LoadFileTask("footer.html")将排队进入无界队列,等待转弯由该Thread执行。
  • RenderPageTask返回一个字符串,其中包含LoadFileTask("header.html")输出,页面正文和LoadFileTask("footer.html")输出的串联。在这三部分中,page是成功获得的RenderPageTask。但是只有通过ExecutorService分配的单个线程执行两项任务后,才能获得其他两个部分。并且只有在call()RenderPageTask方法返回后,线程才会空闲。但是,只有在返回callRenderPageTask后,才会返回LoadFileTask("header.html")LoadFileTask("footer.html")方法。因此,不让LoadFileTask执行将导致 Starvation 。每个等待其他任务完成的任务都会导致 DeadLock

    我希望这可以弄清楚为什么上面的代码中发生线程饥饿死锁。
  • 09-05 16:30