Thread Dump is a very useful tool for diagnosing problems with Java applications. Every Java virtual machine has the ability to generate a thread-dump of the state of all threads at a given point in time. Although the thread dump printed by each Java virtual machine varies slightly, most of them provide a snapshot of the currently active thread and a stack trace of all Java threads in the JVM. The stack information usually contains the full class name and the methods executed and, if possible, the source code line number.
Thread Dump Features
- Can be used under a variety of operating systems.
- Can be used under various Java application servers.
- Can be used in a production environment without affecting system performance.
- the ability to locate problems directly to lines of application code.
Thread Dump Crawl
Generally when the server hangs, crashes or has low performance, you need to capture the server’s thread stack (Thread Dump) for subsequent analysis. In practice, a single dump is often not enough information to confirm the problem. In order to reflect the dynamic change of thread state, we need to do thread dump several times in succession, each time with an interval of 10-20s. It is recommended to generate dump information at least three times, and only if each dump points to the same problem, we can determine the typicality of the problem.
- OS command to get ThreadDump
Be careful, one wrong step can kill the server process. kill -9 command will kill the process.
- The JVM comes with tools to get the thread stack
Thread Dump analysis
Thread Dump information
- Header information: time, JVM information
- Thread INFO message block.
- Java thread statck trace details.
Stack information should be interpreted in reverse: the program executes first on line 7, then on line 6, and so on.
That means the object is locked first, locking the object 0xb3885f60, and then releasing the object lock and entering the waiting state. Why does this happen? Take a look at the following java code example to understand.
As above, the thread is executed by first obtaining the Monitor of the object (corresponding to locked <0xb3885f60>) using synchronized. When obj.wait () is executed, the thread relinquishes ownership of the Monitor and enters the “wait set” queue (corresponding to waiting on <0xb3885f60>).
The state of the thread at the code level is further indicated in the first line of information on the stack, e.g.
Explain as follows.
Thread state analysis
The state of a thread is a very important thing, so the thread dump shows this state. By analyzing this state, you can derive the running status of the thread and thus find possible problems. The state of a thread is defined in the Thread.State enumeration type.
Each thread has a corresponding Thread object in heap memory. thread t = new Thread (); When a Thread object has just been created in heap memory, the thread is in the NEW state before the t.start () method has been called. In this state, the thread is no different from a normal java object, it is just an object in heap memory.
This state means that the thread has all the conditions to run, is in the run queue ready to be scheduled by the OS, or is running. This state is normal, but if the thread stays in this state for a long time, it is not normal. This means that the thread has been running for a long time (performance problem), or the thread has not been given the chance to execute (thread starvation problem).
A thread is waiting for access to a java object’s monitor (also called a built-in lock), i.e., it is waiting to enter a method or block protected by synchronized. synchronized is used to ensure atomicity, and at most one thread can enter the critical area at any given time, and other threads can only wait in line.
The state of the thread that is waiting for a certain event to occur, and only if a specific condition is met will it get the chance to execute. And it is usually another thread that generates this particular event. That is, if a specific event does not occur, then the thread in that state is waiting and cannot get the opportunity to execute. For example.
Thread A calls the obj.wait () method of the obj object, and if no thread calls obj.notify or obj.notifyAll, then there is no way for thread A to resume running; if thread A calls LockSupport.park () and no other thread calls LockSupport.unpark (A), then there is no way for A to resume running. then there is no way for A to resume running. TIMED_WAITING.
Many thread-related classes in J.U.C provide both time-limited and untimed versions of the API. timed_waiting means that the thread has called the time-limited version of the API and is waiting for time to pass. When the wait time has passed, the thread can resume running as well. If a thread enters the WAITING state, a specific event must occur for it to resume; a thread in TIMED_WAITING will resume if a specific event occurs or if the time elapses.
A thread stays in this state when it finishes executing, when it returns normally from executing the run method, or when it throws a runtime exception and ends. At this point the thread is left with only the Thread object, which is useless.
Key state analysis
- Wait on condition: The thread is either sleeping or waiting to be notified by another thread.
This state means that it is either waiting for another condition to occur to wake itself up, or simply that it is calling sleep (n).
At this point the thread state is roughly as follows.
- Waiting for Monitor Entry and in Object.wait (): The thread is waiting to get the lock for an object (some other thread may be holding the lock). This happens if two or more threads try to execute synchronized code. Note that the lock is always for an object and not for individual methods.
In multi-threaded JAVA programs, synchronization between threads, we should talk about Monitor.Monitor is the main means used in Java to achieve mutual exclusion and collaboration between threads, it can be thought of as a lock on an object or class. Every object has one and only one Monitor. The following diagram depicts the relationship between threads and Monitors, as well as the state transition diagram for threads.
As shown above, each Monitor can only be owned by one thread at a given time, that thread is the “ActiveThread” and all other threads are “Waiting Threads”, waiting in two queues The other threads are “Waiting Threads” and are waiting in two queues, “Entry Set” and “Wait Set” respectively. The status of the waiting thread in “Entry Set” is “Waiting for monitor entry”, while the status of the waiting thread in “Wait Set” is “Waiting for monitor entry”. Waiting thread state is “in Object.wait ()”.
Let’s look at the threads inside the “Entry Set”. We call the section of code protected by synchronized the critical zone. When a thread requests to enter the critical zone, it enters the “Entry Set” queue. The corresponding code looks like.
There are two possibilities at this point.
- The monitor is not owned by another thread and there is no other waiting thread in the Entry Set. This thread becomes the owner of the Monitor of the corresponding class or object and executes the code in the critical area.
- The monitor is owned by another thread, and this thread is waiting in the Entry Set queue.
In the first case, the thread will be in the state of “Runnable”, while in the second case, the thread DUMP will show that it is “waiting for monitor entry”. As follows.
Critical areas are set up to ensure the atomicity and integrity of code execution within them. But because the critical zone only allows threads to pass serially at any given time, this is the opposite of the original intent of our multi-threaded program. If synchronized is used extensively, or improperly, in a multi-threaded program, it can cause a large number of threads to wait at the entrance to the critical zone, causing a significant degradation in system performance. If this is found in a threaded DUMP, the source code should be reviewed and the program improved.
Look again at the threads inside the “Wait Set”. **When a thread gets a Monitor and enters the critical zone, if it finds that the conditions for the thread to continue are not met, it calls the wait () method of the object (usually the synchronized object), abandons the Monitor, and enters the “Wait Set” queue. Only when another thread calls notify () or ** notifyAll () on the object does the thread in the “Wait Set” queue get a chance to compete, but only one thread gets the object’s Monitor and returns to the running state. The thread in the “Wait Set” is represented in DUMP as: in Object.wait (). As follows.
- Lock for JDK 5.0
As mentioned above, if the synchronized and monitor mechanisms are not used properly, it may cause performance problems for multi-threaded programs. In JDK 5.0, the Lock mechanism was introduced to give developers more flexibility to develop high-performance concurrent multithreaded programs, replacing the previous synchronized and monitor mechanisms in the JDK. However,** it is important to note that because the Lock class is just an ordinary class, the JVM has no way of knowing the occupancy of the Lock object, so the thread DUMP will not contain information about Lock**, and problems such as deadlocks are not as easy to identify as with synchronized programming.