Skip to main content

Different States of Java Threads


In Java, threads can have States. The Thread.State enum defines the different states that a Java thread can have. This enum defines the following values -
  1. NEW
In the subsequent sections, I provide a brief overview of these states along with possible transitions between them.

States of a Java Thread


This is the default state a thread gets when it is first created.


As soon as a thread starts executing, it moves to the RUNNABLE state. Note that a thread that is waiting to acquire a CPU for execution is still in this state.


A thread moves to the BLOCKED state as soon as it gets blocked waiting for a monitor lock. This can happen in one of the following two ways -
  1. It's waiting to acquire a lock to enter a synchronised block/method.
  2. It's waiting to reacquire the monitor lock of an object on which it invoked the Object.wait method.


A thread moves to this state as a result of invoking one of the following methods -
  1. Object.wait without a timeout
  2. Thread.join without a timeout
  3. LockSupport.park


A thread moves to this state as a result of invoking one of the following methods -


As soon as a thread terminates, it moves to this state.

Possible state transitions

The following diagram shows the possible transitions between different states -

Java Thread Transitions 

As soon as a thread gets scheduled for execution, it moves to the RUNNABLE state. This transition has been shown with the first arrow (marked as 1).

From the RUNNABLE state, a thread can move to any of the BLOCKED, WAITING, TIMED_WAITING, or TERMINATED state. Theoretically speaking, if a thread does not wait to acquire any lock, or does not sleep, or does not invoke any of the methods which makes it wait, it just finishes its execution and directly goes to the TERMINATED state (marked as 2d).

Of course in a practical application, the above scenario is highly unlikely. Often a thread tries to acquire a lock, in which case it moves to the BLOCKED (marked as 2a) state if it has to wait for the lock. Threads also explicitly wait for some preconditions to be true/actions from other threads, in which case they move to the WAITING (marked as 2b) or the TIMED_WAITING (marked as 2c) state, depending on whether the waits were timed or not.

Once a thread moves to the BLOCKED state, the only possible transition that is allowed next is to move to the RUNNABLE state (marked as 3d).

Similarly, the only possible transition from the WAITING state is to move to the BLOCKED state (marked as 3c).

Please note that some of the articles on the internet incorrectly adds a transition from the WAITING to the RUNNABLE state. This is just not correct. A thread can never move to the RUNNABLE state from the WAITING state directly. We can understand the reason for this with an example.

Suppose that we have a thread T which is currently in the RUNNABLE state and holds the monitor lock of three objects a, b, and c, as shown in the diagram below -

Before invoking c.wait()

At this point, T invokes c.wait(), after which it no longer holds the monitor lock of object c -

After invoking c.wait()

As soon as T is notified using an invocation of notify/notifyAll, it stops waiting and competes with other threads (let's say, X and Y) to acquire the monitor lock of c -

After T has been notified with notify/notifyAll

which, according to the definitions above, is the BLOCKED state. Only after acquiring the monitor lock of c, T moves to the RUNNABLE state. Similar reasoning can be applied for the Thread.join() (which internally uses Object.wait()) and LockSupport.park().

Let's get back to our original state transition diagram. As we can see, a thread can move to either the RUNNABLE (marked as 3b) or the BLOCKED (marked as 3a) state from the TIMED_WAITING state. The transition to RUNNABLE is possible in this case because a thread can enter the TIMED_WAITING state after invoking the Thread.sleep method, in which case it retains all the monitor locks it currently holds.

As a thread finishes execution after moving back and forth between the RUNNABLE, BLOCKED, WAITING or TIMED_WAITING state, it moves to the TERMINATED state once and for all.

How do we get the current state of a Thread?

We can use the Thread.getState() method to retrieve the current state of a thread. We can use this value to monitor or debug any concurrency issues that our application might face in production.


In this article we briefly reviewed different states a Java thread can have, and how a thread moves between these states. As always, any feedback/improvement suggestions/comments is highly appreciated!


Popular posts from this blog

Dealing with Java's LocalDateTime in JPA

A few days ago I ran into a problem while dealing with a LocalDateTime attribute in JPA. In this blog post I will try to create a sample problem to explain the issue, along with the solution that I used.
Consider the following entity, which models an Employee of a certain company -
@Entity @Getter @Setter public class Employee { @Id @GeneratedValue private Long id; private String name; private String department; private LocalDateTime joiningDate; }
I was using Spring Data JPA, so created the following repository -
@Repository public interface EmployeeRepository extends JpaRepository<Employee, Long> { }
I wanted to find all employees who have joined the company at a particular date. To do that I extended my repository from JpaSpecificationExecutor - @Repository public interface EmployeeRepository extends JpaRepository<Employee, Long>, JpaSpecificationExecutor<Employee> { }
and wrote a query like below -
@SpringBootTest @RunWith(SpringRunne…

Clean Code from the trenches - Validation

Let's directly start with an example. Consider a simple web service which allows clients to place order to a shop. A very simplified version of the order controller could look something like below -

@RestController @RequestMapping(value = "/", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public class OrderController { private final OrderService orderService; public OrderController(OrderService orderService) { this.orderService = orderService; } @PostMapping public void doSomething(@Valid @RequestBody OrderDTO order) { orderService.createOrder(order); } }
And the corresponding DTO class -

@Getter @Setter @ToString public class OrderDTO { @NotNull private String customerId; @NotNull @Size(min = 1) private List<OrderItem> orderItems; @Getter @Setter @ToString public static class OrderItem { private String menuId; private String description; private String pric…

Java Tips: Creating a Monitoring-friendly ExecutorService

In this article we will be extending an ExecutorService implementation with monitoring capabilities. This monitoring capability will help us to measure a number of pool parameters i.e., active threads, work queue size etc. in a live production environment. It will also enable us to measure task execution time, successful tasks count, and failed tasks count.

Monitoring Library As for the monitoring library we will be using Metrics. For the sake of simplicity we will be using a ConsoleReporter which will report our metrics to the console. For production-grade applications, we should use an advanced reporter (i.e., Graphite reporter). If you are unfamiliar with Metrics, then I recommend you to go through the getting started guide.

Let's get started.

Extending the ThreadPoolExecutor We will be using ThreadPoolExecutor as the base class for our new type. Let's call it MonitoredThreadPoolExecutor. This class will accept a MetricRegistry as one of its constructor parameters -

public …