The Limitations of the ps Command
When a Linux server experiences a massive CPU spike, system administrators instinctively run the ps aux or top commands to identify the offending process. The output will clearly show that the java process or the mysqld daemon is consuming 99% of the CPU.
However, modern applications do not run as a single monolithic block; they are multi-threaded. A single Java application (represented by one Process ID) might actually consist of 500 individual worker threads running concurrently. The standard ps command aggregates all CPU usage into a single line for the parent process. It cannot tell you which specific thread out of the 500 is caught in an infinite loop and burning the CPU.
To dive deeper and expose the individual threads running beneath a parent process, you must use the -T flag with the ps command.
Viewing All Threads System-Wide
To view every single thread currently executing on the entire Linux system, you can combine the standard -e (every process) and -f (full formatting) flags with the -T flag.
ps -efT
The output will be massive, but pay close attention to the column headers.
UID PID SPID PPID C STIME TTY TIME CMD
root 1200 1200 1 0 08:00 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1201 1201 1200 0 08:00 ? 00:00:00 /usr/sbin/apache2 -k start
www-data 1201 1210 1200 99 08:01 ? 00:15:22 /usr/sbin/apache2 -k start
www-data 1201 1211 1200 0 08:01 ? 00:00:01 /usr/sbin/apache2 -k start
Understanding SPID
Notice the new column named SPID (Thread ID, sometimes displayed as LWP or Lightweight Process). In the example above, the Apache web server has a primary Process ID (PID) of 1201. However, there are multiple rows for PID 1201. Each row represents a distinct thread, identified by its unique SPID (1201, 1210, 1211).
Looking at the C (CPU utilization) column, it is immediately obvious that SPID 1210 is the rogue thread consuming 99% of the processor, while the other threads in the pool are idle.
Targeting a Specific Process
Running a system-wide trace is usually too noisy. If you already know that the Java application (PID 4567) is the culprit, you can filter the command to only show the threads belonging to that specific parent process.
ps -T -p 4567
This provides a clean, isolated list of the threads strictly associated with your application, allowing developers to map the rogue SPID back to their application logs to identify exactly which function (e.g., a database query or an image processing task) is causing the bottleneck.
The htop Alternative
If you prefer an interactive, real-time graphical interface rather than a static command-line dump, you can use the popular htop utility.
By default, htop hides threads to keep the interface clean. Once htop is running, simply press Shift + H on your keyboard. The interface will instantly expand, turning every process into a tree view that reveals all of its active, color-coded threads, making rogue thread identification incredibly intuitive.