简体   繁体   中英

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?

What does "parking to wait for" mean? And what is "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.

Find below a snippet for demonstration

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

javac Future.java
java Future

run in session 2

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

note: 12345 is the PID of the running java Future process

content of 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

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 . So you might reach the line task.get(...) before the task is actually executed. Your thread pool also might not able to run numberOfThreads() threads at the same time.

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. As the first task is a long running one, we step into the situation you discover.

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

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

main - is the dump for future2.get(30, TimeUnit.SECONDS) , which waits for the result of future2 , which actually is not yet started.

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. 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.

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. 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. 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.

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. 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.

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. That makes the thread2 go into the BLOCKED state .

What does "0x00007f445cd1a000" indicate?

It indicates the condition variable that the thread is waiting to become true.

What does "parking to wait for" mean? And what is "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 . (I am not sure what 0x00007f59c9e1c278 is).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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