简体   繁体   English

分析Java线程转储

[英]Analyzing the java thread dumps

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

I have spent the last day trying to understand what this actually means. 我花了最后一天试图了解这实际上意味着什么。 There is not enough information about this, or I could not find anything useful. 没有足够的信息,或者我找不到任何有用的信息。

What does "waiting on condition" mean? “等待条件”是什么意思? Are we waiting on a monitor ? 我们在等待监视器吗? what does "0x00007f445cd1a000" indicate? “ 0x00007f445cd1a000”表示什么?

What does "parking to wait for" mean? “停车等待”是什么意思? And what is "0x00007f59c9e1c278"? 什么是“ 0x00007f59c9e1c278”?

Source code: 源代码:

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

This might point to a coding problem. 这可能指向编码问题。 The code waits for the completion of a FutureTask which is not yet executed. 该代码等待尚未执行的FutureTask的完成。

Find below a snippet for demonstration 在下面的代码段中进行演示

Future.java 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);
    }
}

run in session 1 在会话1中运行

javac Future.java
java Future

run in session 2 在会话2中运行

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

note: 12345 is the PID of the running java Future process 注意: 12345是正在运行的java Future进程的PID

content of jstack.12345.log 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)

edit Based on the posted code snippet the described situation can happen quite easily. 编辑根据发布的代码段,描述的情况很容易发生。 Referring to the javadoc of Executor.execute 引用Executor.execute的javadoc

Executes the given command at some time in the future. 在将来的某个时间执行给定命令。

at some time in the future which means not immediately at the invocation of execute . at some time in the future这意味着不是立即调用execute So you might reach the line task.get(...) before the task is actually executed. 因此,您可能在实际执行任务之前先到达task.get(...)行。 Your thread pool also might not able to run numberOfThreads() threads at the same time. 您的线程池也可能无法同时运行numberOfThreads()线程。

A small example to demonstrate (run the same commands as described earlier). 一个小示例进行演示(运行与前面所述相同的命令)。 We create a thread pool which executes only one task at the time. 我们创建一个线程池,该线程池一次仅执行一个任务。 We assign two tasks to that pool. 我们向该池分配两个任务。 Immediately after calling executor.execute(..) for both tasks we wait for the result of the second task. 在为两个任务调用executor.execute(..) ,我们立即等待第二个任务的结果。 As the first task is a long running one, we step into the situation you discover. 由于第一个任务是长期运行的任务,因此我们进入您发现的情况。

Future.java 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);
    }
}

content of jstack.12345.log 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 - is the dump for future1 which currently sleeps (to simulate the long running task) pool-1-thread-1future1的转储,当前正在休眠(以模拟长时间运行的任务)

main - is the dump for future2.get(30, TimeUnit.SECONDS) , which waits for the result of future2 , which actually is not yet started. main -是转储future2.get(30, TimeUnit.SECONDS)它等待的结果future2 ,这实际上是尚未开始。

Thread Dumps (an excellent debugging tool) on the Oracle Hotspot JVM should be better documented to throw some light on answers to these questions, but the basics are pretty much based on Java's built-in support for multiple threads. 应该更好地记录Oracle Hotspot JVM上的线程转储(一种出色的调试工具),以便对这些问题的答案有一些了解,但是这些基本知识是基于Java对多个线程的内置支持。 Here's my take on your questions: 这是我对您的问题的看法:

What does "waiting on condition" mean? “等待条件”是什么意思?

In short, it means that the thread in question has called the Object.wait() method on the associated monitor. 简而言之,这意味着所讨论的线程已在关联的监视器上调用了Object.wait()方法。

One of the central features of Java's concurrency support is the low-level construct called wait/notify which is used as some kind of a vehicle for inter-thread communication. Java并发支持的主要功能之一是称为wait/notify的低级构造,它用作某种类型的线程间通信工具。 When the threads are using shared mutable state , in a thread-safe program, they should ensure that that state satisfies some condition before they operate on it (the state). 当线程使用共享的可变状态时 ,在线程安全的程序中,它们应确保该状态满足某些条件,然后再对其进行操作(状态)。

An example of this in the classic Producer-Consumer pattern is that the Consumer thread waits for some shared queue to have at least an item to consume. 经典的Producer-Consumer模式中的一个示例是,Consumer线程等待某个共享队列中至少要消耗一个项目。 Thus, for the Consumer thread to do any meaningful work, it relies on other (eg Producer) threads to produce items. 因此,对于消费者线程执行任何有意义的工作,它依赖于其他(例如生产者)线程来产生项目。 To make this work correctly, the Consumer thread enters the monitor on the queue (entering the critical section, holding the exclusive lock) but then spins (should have a while loop) on some condition to be true. 为了使其正常工作,消费者线程在队列上进入监视器(进入临界区,持有排他锁),但随后在某些条件为真while旋转(应该有一个while循环)。

If the condition is false, it immediately gives up the lock on the monitor (exits the monitor) and requests that it be somehow kept in mind when next time the JVM picks a thread to enter the same monitor. 如果条件为假,它将立即放弃对监视器的锁定(退出监视器),并要求在下次JVM选择线程进入同一监视器时以某种方式牢记该锁。 You see, without giving up the lock, there would be no progress. 您会看到,不放弃锁,就不会有任何进展。 Java implements this via the notion of a wait-set associated with a monitor. Java 通过与监视器关联的等待集的概念来实现此目的

Are we waiting on a monitor ? 我们在等待监视器吗?

No. Waiting on, or rather waiting to enter the monitor would block the thread that is waiting. 不能。等待,或者等待进入监视器将阻塞正在等待的线程。 Here's what the thread dump snippet of such a (blocked) thread looks like: 这样的(阻塞的)线程的线程转储代码片段如下所示:

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

In this example dump, the thread thread2 wants to acquire the lock currently (at the time of thread dump) held by some other thread. 在此示例转储中,线程thread2希望获取某个其他线程当前持有的锁(在线程转储时)。 That makes the thread2 go into the BLOCKED state . 这使thread2进入BLOCKED状态

What does "0x00007f445cd1a000" indicate? “ 0x00007f445cd1a000”表示什么?

It indicates the condition variable that the thread is waiting to become true. 它指示线程正在等待变为真的条件变量

What does "parking to wait for" mean? “停车等待”是什么意思? And what is "0x00007f59c9e1c278"? 什么是“ 0x00007f59c9e1c278”?

All threads waiting on a condition variable to become true have a very similar looking snippet in the thread dump. 等待条件变量变为真的所有线程在线程转储中都有一个非常相似的片段。 The actual wait support is implemented via LockSupport.park() and Unsafe.park . 实际的等待支持是通过LockSupport.park()Unsafe.park (I am not sure what 0x00007f59c9e1c278 is). (我不确定0x00007f59c9e1c278是什么)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM