Do You Know What Your Java Threads Are Doing?

What is a Java Thread and Why is It Used?

Java Thread Monitoring Tool A thread, in the context of Java, is the path followed when executing a program. All Java programs have at least one thread, known as the main thread, which is created by the Java Virtual Machine (JVM) at the program’s start, when the main() method is invoked with the main thread.

In Java, creating a thread is accomplished by implementing an interface and extending a class. Every Java thread is created and controlled by the java.lang.Thread class.

A single-threaded application has only one thread and can handle only one task at a time. To handle multiple tasks in parallel, multi-threading is used: multiple threads are created, each performing a different task.

Most commercial applications use multi-threading extensively. This is done for several reasons:

  • For faster processing of background/batch tasks: When multiple tasks must be performed simultaneously, multi-threading allows the different tasks to proceed in parallel. The overall processing time is reduced as a result.
  • To take advantage of modern processors: Most modern systems have multiple processors and each processor has multiple cores. Multi-threading allows different threads to be run by different processors, thereby allowing the system resources to be more efficiently used.
  • For reducing response times: Users expect applications to be fast. By breaking the processing needed for a request into smaller chunks and having different threads handle the processing in parallel, response time can be reduced.
  • To serve multiple users at the same time: Application servers like Tomcat, JBoss, Oracle WebLogic and IBM WebSphere are expected to support thousands of users in parallel. Multi-threading is the only way this can be achieved. One thread is spawned by the application server for each request to be handled.
Multi Thread ServerUnderstanding thread processing in the JVM

Why Should You Monitor Java Threads?

Java applications in production can have hundreds or thousands of threads running in parallel. When an issue is detected – e.g., the JVM is taking up very high CPU resources – an obvious question is which thread is causing the CPU spike? And an immediate next question is which code snippet is the thread executing? While it is important to report this information in real-time, it is also important that these details are made available for historical analysis. For instance, your application could have had a CPU spike at 2 am and become unresponsive, forcing your operations team to restart the server. While this would have solved the problem temporarily, what was the cause and how do we prevent this issue from re-occurring? Having the details of what threads in the JVM were running at 2 am and which thread was taking up CPU is a key to being able to diagnose the application performance issue.

JVM High CPU GraphCPU spike in JVM caused by a high CPU thread
JVM High CPU GraphLooking at the JVM stack trace to isolate the thread causing high CPU usage

Multiple threads in a JVM can be performing similar tasks. For instance, a configuration file may need to be updated when a request is processed. Since multiple threads access the same configuration file, it is essential to synchronize the threads, so only one thread at any time can be updating the configuration file. While synchronization ensures consistency of the common resource (in this case, the configuration file), it also introduces the possibility of delays in processing requests. Requests being processed by an application server must wait until the corresponding thread is allowed to enter the synchronized block. Excessive use of synchronized blocks can result in a high percentage of the processing time of a request being spent waiting for access to synchronized blocks of code. To ensure great user experience, it is important to ensure that blocking due to thread synchronization is at a minimum.

At the same time, it is also important to track the number of threads being spawned in the JVM. If too many threads are created in parallel, the JVM memory must be sufficiently sized to handle this load. If not, application performance will suffer. Administrators also must track cases of thread leaks – i.e., instances when the number of threads in the JVM keep on increasing and ultimately cause the JVM to crash.

JVM Sizing Tip: If too many threads are created in parallel, the #JVM memory must be sufficiently sized to handle this load. If not, application performance will suffer.
#Java
Click to Tweet

Application servers have thread pools where threads are created and remain waiting for new user requests. The thread pools have maximum limits on the number of threads in each pool. If this limit on the maximum number of threads that can be executing in a pool is reached, new requests to the application server will be rejected. Hence, it is important to monitor the number of current threads in each pool.

IT performance monitoring dashboardUnderstanding various states of a Java thread

Monitoring Java Threads: Key Questions to Answer

QuestionsModern JVMs provide JMX interfaces that allow monitoring tools to track thread activity in the JVM. The key questions you should try to answer with your Java application performance monitoring solution include:

  • How many threads are currently running in the JVM?
  • How many threads are in each state: runnable, running, timed waiting, blocked, timed waiting, etc.?
  • What line of code is each thread executing and what is the stack trace?
  • Is any thread taking up excessive CPU resources and if so, what code block is being executed?
  • Has there been a growth of threads in the JVM over time?
  • Are there many blocked threads? Which class are these threads blocked in, on which variable? Which thread is blocking these threads and what code is it executing?
  • Are there deadlocked threads in the JVM?
  • What thread pools are configured in the application server and what are the max limits?
  • What is the utilization of each thread pool? Is any pool’s current usage close to its maximum?

Helpful Resources