3
//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がこことどこでどのように発生しているかを見つけるのを手伝ってください。前もって感謝します。

4

3 に答える 3

12

デッドロックと飢餓は次の行で発生しています。

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

デッドロックにつながるステップ:

  1. 実装されたクラスexecを介してページをレンダリングするためのタスクが送信されます。CallableRenderPageTask
  2. execRenderPageTaskを別々に開始しました。これは、順番に送信された他のタスクを実行するThread唯一のものです。Threadexec
  3. さらに2つのタスクの内部call()メソッドがに送信されます。最初はで、2番目はです。ただし、ここで説明するコードを介して取得されたExecutorServiceは、無制限のqueueThreadで動作する単一のワーカースレッドを使用し、 スレッドはすでにRenderPageTaskに割り当てられているため、無制限のキューにキューに入れられ、その順番が実行されるのを待ちます。RenderPageTaskexecLoadFileTask("header.html")LoadFileTask("footer.html")execExecutors.newSingleThreadExecutor(); LoadFileTask("header.html")LoadFileTask("footer.html")Thread
  4. RenderPageTaskLoadFileTask("header.html")の出力、ページの本文、およびの出力の連結を含む文字列を返し ますLoadFileTask("footer.html")。これらの3つの部分のうち、pageによって正常に取得されRenderPageTaskます。ただし、他の2つの部分は、によって割り当てられた単一のスレッドによって両方のタスクが実行された後にのみ取得できますExecutorService。そして、スレッドはreturnscall()のメソッドの後でのみ解放されます。RenderPageTaskただし、callのメソッドは後にRenderPageTaskのみ返され、返されます。ですから、実行させないことは飢餓につながります。そして、他のタスクの完了を待っている各タスクがDeadLock につながることを願っています。これにより、上記のコードでスレッド不足のデッドロックが発生している理由が明らかになることを願っています。LoadFileTask("header.html")LoadFileTask("footer.html")LoadFileTask

于 2013-02-02T13:19:53.967 に答える
0

私が見るエグゼキュータはシングルスレッドエグゼキュータであり、2つのタスクを実行する必要があります。ただし、これら2つのタスクは相互に依存しておらず、実行の順序は重要ではないようです。したがって、returnステートメントは、1つのタスクを完了してから別のタスクを完了するために必要なだけFuture.get呼び出しで一時停止します。

表示するコードでデッドロックは発生しません。

ただし、コード(RenderPageTask)にもう1つのタスクがありますが、どのエグゼキューターが実際にそのコードを実行しているかが明確ではありません。同じシングルスレッドエグゼキュータの場合、メインタスクが戻る前に2つの送信されたタスクを処理できないため、デッドロックが発生する可能性があります(このタスクは、2つのタスクが処理された後にのみ戻ることができます)。

于 2013-02-02T10:49:36.170 に答える
0

その理由は、コード自体からではなく、コードのコピー元の元の本からは明らかではありません。RenderPageTaskは、ページヘッダーとフッターをフェッチするために2つの追加タスクをエグゼキューターに送信します...

RenderPageTaskがnewSingleThreadExecutorから独立したタスクである場合、デッドロックはまったく発生しません。

于 2018-02-02T21:30:16.933 に答える