分析java线程转储

时间:2016-04-22 08:24:49

标签: java multithreading jstack

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

2 个答案:

答案 0 :(得分:2)

这可能指向编码问题。代码等待完成尚未执行的FutureTask

在下面找到演示片段

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()个线程。

演示的一个小例子(运行与前面描述的相同的命令)。我们创建一个线程池,当时只执行一个任务。我们将两个任务分配给该池。在为两个任务调用executor.execute(..)之后,我们立即等待第二个任务的结果。由于第一项任务是长期运行,我们会介入您发现的情况。

<强> 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的结果,实际上尚未启动。

答案 1 :(得分:2)

应该更好地记录Oracle Hotspot JVM上的线程转储(一个优秀的调试工具),以便对这些问题的答案有所了解,但基本知识几乎基于Java对多线程的内置支持。以下是我对你问题的看法:

  

&#34;等待条件&#34;意思?

简而言之,这意味着相关主题已在关联的监视器上调用Object.wait()方法。

Java的并发支持的一个核心功能是名为wait/notify的低级构造,它被用作某种线程间通信的工具。当线程使用共享可变状态时,在线程安全程序中,它们应该确保该状态在对它进行操作(状态)之前满足某些条件。

经典的Producer-Consumer模式中的一个示例是,Consumer线程等待某个共享队列至少要使用一个项目。因此,对于Consumer线程来做任何有意义的工作,它依赖于其他(例如Producer)线程来生成项目。为了使这个工作正常,Consumer线程进入队列中的监视器(进入临界区,持有独占锁)但在某些条件下旋转(应该有一个while循环)为真。

如果条件为false,它会立即放弃监视器上的锁(退出监视器),并在下次JVM选择一个线程进入时请求以某种方式记住它。 相同的监视器。你看,没有放弃锁定,就没有进步。与监视器关联的Java implements this via the notion of a wait-set

  

我们在监视器上等吗?

没有。等待<或>等待进入监视器将阻止正在等待的线程。这是这种(被阻止的)线程的线程转储片段的样子:

"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想要获取当前(在线程转储时)由某个其他线程持有的锁。这使thread2进入BLOCKED state

  

&#34; 0x00007f445cd1a000&#34;指示?

它表示线程等待变为真的条件变量

  

&#34;什么停车等待&#34;意思?什么是&#34; 0x00007f59c9e1c278&#34;?

在条件变量上等待的所有线程在线程转储中具有非常相似的外观片段。实际的等待支持是通过LockSupport.park()Unsafe.park实现的。 (我不确定 0x00007f59c9e1c278 是什么)。