1
"Star Builder 129" daemon prio=10 tid=0x00007f41bd8f6000 nid=0x152b0 waiting on condition [0x00007f445cd1a000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00007f59c9e1c278> (a java.util.concurrent.FutureTask)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
        at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:422)
        at java.util.concurrent.FutureTask.get(FutureTask.java:199)

私はこれが実際に何を意味するのかを理解するために最後の日を費やしました. これに関する十分な情報がないか、有用なものが見つかりませんでした。

「状態待ち」とは?モニターで待っていますか?「0x00007f445cd1a000」は何を示していますか?

「待つ駐車場」とは?そして「0x00007f59c9e1c278」とは?

ソースコード:

        List<FutureTask<List<FileStatus>>> tasks = new LinkedList<FutureTask<List<FileStatus>>>();
    for(int idx = 0, len = Math.max(1,numberOfThreads()); idx < len; ++idx) {
        StatusWorker worker = new StatusWorker(this, qualifiedPath, userFilter, prefixQueue, prefixCounter, statusCounter);
        FutureTask<List<FileStatus>> task = new FutureTask<List<FileStatus>>(worker);
        threadPool.execute(task);
        tasks.add(task);
    }

    try {
        List<FileStatus> statuses = new LinkedList<FileStatus>();

        for(FutureTask<List<FileStatus>> task : tasks) {
            statuses.addAll(task.get(FILE_LISTING_TIMEOUT, TimeUnit.SECONDS));
            logger.debug("Result from task [{}]", task);
        }
4

2 に答える 2

2

これは、コーディングの問題を示している可能性があります。FutureTaskコードは、まだ実行されていないa の完了を待ちます。

デモンストレーション用のスニペットの下を見つけます

Future.java

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

public class Future {

    public static void main(String[] args) throws Exception {
        FutureTask<String> future = new FutureTask<>(
                new Callable<String>() {
                    @Override
                    public String call() throws InterruptedException {
                        return "foo";
                    }
                });
        String get = future.get(30, TimeUnit.SECONDS);
        System.out.println("get = " + get);
    }
}

セッション 1 で実行

javac Future.java
java Future

セッション 2 で実行

$ jps
...
12345 Future
jstack -l 12345 > jstack.12345.log

注: 12345は実行中のjava Futureプロセスの PID です

jstack.12345.log の内容

    "main" #1 prio=5 os_prio=0 tid=0x000000000273b000 nid=0x2b24 waiting on condition [0x0000000002abf000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000781973910> (a java.util.concurrent.FutureTask)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
        at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:426)
        at java.util.concurrent.FutureTask.get(FutureTask.java:204)
        at Future.main(Future.java:19)

編集投稿されたコード スニペットに基づいて、説明されている状況は非常に簡単に発生する可能性があります。Executor.executeの javadoc を参照

将来のある時点で指定されたコマンドを実行します。

at some time in the futureこれは、 の呼び出し直後ではないexecuteことを意味します。task.get(...)そのため、タスクが実際に実行される前に行に到達する可能性があります。また、スレッド プールが同時にスレッドを実行できない場合もありますnumberOfThreads()

デモ用の小さな例 (前述と同じコマンドを実行します)。一度に 1 つのタスクのみを実行するスレッド プールを作成します。そのプールに 2 つのタスクを割り当てます。両方のタスクを呼び出した直後にexecutor.execute(..)、2 番目のタスクの結果を待ちます。最初のタスクは長時間実行されるタスクであるため、発見した状況に踏み込みます。

Future.java

public class Future {

    public static void main(String[] args) throws Exception {
        FutureTask<String> future1 = new FutureTask<>(
                () -> {
                    System.out.println("future1");
                    TimeUnit.SECONDS.sleep(50);
                    return "finished future1";
                });

        FutureTask<String> future2 = new FutureTask<>(
                () -> {
                    System.out.println("future2");
                    return "finished future2";
        });

        ExecutorService executor = Executors.newFixedThreadPool(1);
        executor.execute(future1);
        executor.execute(future2);

        String get = future2.get(30, TimeUnit.SECONDS);
    }
}

jstack.12345.log の内容

"pool-1-thread-1" #9 prio=5 os_prio=0 tid=0x00007ff50811c000 nid=0x5a5c waiting on condition [0x00007ff4e7365000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at java.lang.Thread.sleep(Thread.java:340)
    at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
    at concurrent.Future$1.call(Future.java:19)
    at concurrent.Future$1.call(Future.java:15)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

"main" #1 prio=5 os_prio=0 tid=0x00007ff50800a000 nid=0x5a4d waiting on condition [0x00007ff50e314000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000ec03dda8> (a java.util.concurrent.FutureTask)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:426)
    at java.util.concurrent.FutureTask.get(FutureTask.java:204)
    at concurrent.Future.main(Future.java:36)

pool-1-thread-1- 現在スリープしているダンプですfuture1(長時間実行されるタスクをシミュレートするため)。

main- は のダンプで、実際にはまだ開始されていないfuture2.get(30, TimeUnit.SECONDS)の結果を待ちます。future2

于 2016-04-22T09:03:33.187 に答える
2

Oracle Hotspot JVM の Thread Dumps (優れたデバッグ ツール) は、これらの質問に対する答えを明らかにするために、より適切に文書化されている必要がありますが、基本は、Java の組み込みのマルチスレッド サポートにほとんど基づいています。あなたの質問に対する私の見解は次のとおりです。

「状態待ち」とは?

つまり、問題のスレッドがObject.wait()関連するモニターでメソッドを呼び出したことを意味します。

wait/notifyJava の同時実行サポートの中心的な機能の 1 つは、スレッド間通信の何らかの手段として使用される低レベルの構造体と呼ばれるものです。スレッドが共有可変状態を使用している場合、スレッドセーフなプログラムでは、その状態 (状態) を操作する前に、その状態が何らかの条件を満たしていることを確認する必要があります。

従来の Producer-Consumer パターンでのこの例は、Consumer スレッドが共有キューに少なくとも 1 つのアイテムが消費されるのを待機することです。したがって、Consumer スレッドが意味のある作業を行うためには、他の (Producer などの) スレッドに依存してアイテムを生成します。これを正しく機能させるために、コンシューマー スレッドはキューのモニターに入り (クリティカル セクションに入り、排他ロックを保持しwhileます)、何らかの条件が true になるとスピンします (ループが必要です)。

条件が false の場合、モニターのロックをすぐに放棄し (モニターを終了し)、次に JVM がスレッドを選択して同じモニターに入るときに、何らかの方法でロックを保持するように要求します。ロックを放棄しなければ、進歩はありません。Javaは、モニターに関連付けられた待機セットの概念を介してこれを実装します。

モニターで待っていますか?

いいえ。待機中、またはモニターに入るのを待機していると、待機中のスレッドがブロックされます。このような (ブロックされた) スレッドのスレッド ダンプ スニペットは次のようになります。

"thread2" #12 prio=5 os_prio=31 tid=0x00007ff51607d000 nid=0x5903 waiting for monitor entry [0x000000012f693000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at juc.SyncRace$Lock.sleep(SyncRace.java:11)
    - waiting to lock <0x000000076b021630> (a java.lang.Class for juc.SyncRace$Lock)

このダンプの例では、スレッドは、thread2他のスレッドが現在 (スレッド ダンプの時点で) 保持しているロックを取得しようとしています。これにより、thread2BLOCKED状態になります。

「0x00007f445cd1a000」は何を示していますか?

スレッドが真になるのを待っている条件変数を示します。

「待つ駐車場」とは?そして「0x00007f59c9e1c278」とは?

条件変数が true になるのを待っているすべてのスレッドは、スレッド ダンプに非常によく似たスニペットを持っています。実際の待機サポートは、 および を介して実装されLockSupport.park()ますUnsafe.park。(0x00007f59c9e1c278が何であるかはわかりません)。

于 2016-04-23T01:41:08.603 に答える