evaluation of a java thread dump
I got a thread dump of one of my processes. It has a bunch of these threads. I guess they are keeping a bunch of memory so I am getting OOM.
"Thread-8264" prio=6 tid=0x4c94ac00 nid=0xf3c runnable [0x4fe7f000]
java.lang.Thread.State: RUNNABLE
at java.util.zip.Inflater.inflateBytes(Native Method)
at java.util.zip.Inflater.inflate(Inflater.java:223)
- locked <0x0c9bc640> (a java.util.zip.Inflater)
at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.read(ZipArchiveInputStream.java:235)
at com.my.ZipExtractorCommonsCompress.extract(ZipExtractorCommonsCompress.java:48)
at com.my.CustomThreadedExtractorWrapper$ExtractionThread.run(CustomThreadedExtractorWrapper.java:151)
Locked ownable synchronizers:
- None
"Thread-8241" prio=6 tid=0x4c94a400 nid=0xb8c runnable [0x4faef000]
java.lang.Thread.State: RUNNABLE
at java.util.zip.Inflater.inflateBytes(Native Method)
at java.util.zip.Inflater.inflate(Inflater.java:223)
- locked <0x0c36b808> (a java.util.zip.Inflater)
at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.read(ZipArchiveInputStream.java:235)
at com.my.ZipExtractorCommonsCompress.extract(ZipExtractorCommonsCompress.java:48)
at com.my.CustomThreadedExtractorWrapper$ExtractionThread.run(CustomThreadedExtractorWrapper.java:151)
Locked ownable synchronizers:
- None
I am trying to find out how it arrived to this situation. CustomThreadedExtractorWrapper is a wrapper class that fires a thread to do some work (ExtractionThread, which uses ZipExtractorCommonsCompress to extract zip contents from a compressed stream). If the task is taking too long, ExtractionThread.interrupt()
is called to cancel the operation.
I can see in my logs that the cancellation happened 25 times. And I see 21 of these threads in my dump. My questions:
- What is the status of these threads? Alive and running? Blocked somehow?
- They did not die with .interrupt() apparently? Is there a sure way to really kill a thread?
- What does really mean 'locked ' in the stack trace?
Line 223 in Inflater.java is:
public synchr开发者_Go百科onized int inflate(byte[] b, int off, int len) {
...
//return is line 223
return inflateBytes(b, off, len);
}
"locked" means that they own a monitor; namely, the method is synchronized
, and the thread dump shows the address of the instance on which synchronization is performed.
You can try to kill a thread with Thread.stop()
, but the thread may resist, and it is inherently unsafe, deprecated, and very bad. Do not do it. Besides, I am not sure it works when the thread is in a native method, as is the case here.
Thread.interrupt()
nudges the target thread. The thread will notice it the next time it either looks at the interrupt flag explicitly, or performs some potentially blocking operation (I/O, or wait()
). The thread may catch the exception and ignore it.
Your threads are "runnable": they are not blocked. Inflater.inflate()
is not a blocking function anyway; it performs in-memory computations only. There may be a bug in the native implementation (Inflater.inflateBytes()
, but that's not very probable because this relies on Zlib, which is a very stable piece of code). More plausibly, one of the callers (e.g. your ZipExtractorCommonsCompress
class) is stuck in a loop in which it asks the Zip extractor to process zero more bytes, and does not understand that it should wait for some more data before trying again.
All these threads are in runnable state
interrupt will not a kill a thread... it is just a flag to indicate whether the thread is interrupted, methods sleep , wait and all will throw InteruptedException on thread interrupt. If you want to stop the thread on interuption check for the method and isInterupted() and finish all the work in that thread
locked indicates that one particular object is locked by that thread
If possible I would recommend you try to use the jvisualvm (its in the bin folder of the JDK install). It can connect to any local java process and provide you with thread information and memory information (usage, allocated objects, etc). The interface is much easier to interpret than the console dumps. For your questions:
The definitions of Thread.State are in the API:
NEW - A thread that has not yet started is in this state.
RUNNABLE - A thread executing in the Java virtual machine is in this state.
BLOCKED - A thread that is blocked waiting for a monitor lock is in this state.
WAITING - A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
TIMED_WAITING - A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
TERMINATED - A thread that has exited is in this state.
So the two threads in your trace above are alive (note runnable means that they can run, not necessarily that they are running, i.e. the OS scheduler may have them paused while another thread is executing).
Possible ways to "kill" a thread:
- Have an uncaught exception
- call Thread's stop()
- Have the thread complete execution normally (i.e. exit from run()).
For your third question, I am not sure, but I believe that is a reference to an internal lock that the thread is holding.
Is there a sure way to really kill a thread?
No, there is not.
As you have observed Thread.interrupt()
advises a thread to stop, but it may not notice, or it may decide to pay no attention.
The only other alternative is Thread.stop()
, and that is deprecated because it can seriously destabilize an application. Specifically, Thread.stop()
causes all of the threads locks to be released, without any guarantee that the state guarded by the locks is in a fit state to be visible. At the same time, the unexpected exception means that the methods that were interrupted by the stop()
don't get a chance to (for example) notify()
other threads that are waiting. Finally, it is possible for a thread to catch (and not rethrow) the ThreadDeath
exception object, causing the stop()
to not stop the thread at all.
In short calling Thread.stop()
is a really, really bad idea.
精彩评论