In this section, we will explore the lifecycle of a thread in Java. Understanding the thread lifecycle is crucial for managing threads effectively in a multithreaded environment. The lifecycle of a thread in Java can be broken down into several states:
- New
- Runnable
- Blocked
- Waiting
- Timed Waiting
- Terminated
Let's delve into each of these states in detail.
- New
A thread is in the "New" state when it is created but not yet started. This is the initial state of a thread.
In the above code, the thread is created but not started, so it is in the "New" state.
- Runnable
A thread moves to the "Runnable" state when the start()
method is called. In this state, the thread is ready to run and is waiting for the CPU to allocate time for execution.
Once the start()
method is called, the thread transitions from the "New" state to the "Runnable" state.
- Blocked
A thread enters the "Blocked" state when it is waiting to acquire a monitor lock to enter or re-enter a synchronized block/method.
If a thread tries to enter a synchronized method and the lock is already held by another thread, it will be blocked until the lock is released.
- Waiting
A thread is in the "Waiting" state when it is waiting indefinitely for another thread to perform a particular action. This can happen in several scenarios, such as when a thread calls Object.wait()
.
In the above code, the thread will wait indefinitely until another thread calls lock.notify()
or lock.notifyAll()
.
- Timed Waiting
A thread is in the "Timed Waiting" state when it is waiting for another thread to perform an action for a specified waiting time. This can happen when a thread calls methods like Thread.sleep(long millis)
, Object.wait(long timeout)
, or Thread.join(long millis)
.
In the above code, the thread will be in the "Timed Waiting" state for 1 second.
- Terminated
A thread is in the "Terminated" state when it has completed its execution. This can happen either because the thread has finished executing its run()
method or because it was terminated by an exception.
Once the run()
method completes, the thread transitions to the "Terminated" state.
Thread Lifecycle Diagram
Here is a visual representation of the thread lifecycle:
Practical Example
Let's see a practical example that demonstrates the different states of a thread.
public class ThreadLifecycleDemo { public static void main(String[] args) { Thread thread = new Thread(() -> { try { System.out.println("Thread is in Runnable state"); Thread.sleep(1000); // Timed Waiting state synchronized (ThreadLifecycleDemo.class) { System.out.println("Thread is in Blocked state"); ThreadLifecycleDemo.class.wait(); // Waiting state } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread is in Terminated state"); }); System.out.println("Thread is in New state"); thread.start(); } }
In this example:
- The thread starts in the "New" state.
- When
start()
is called, it moves to the "Runnable" state. - It then enters the "Timed Waiting" state when
Thread.sleep(1000)
is called. - After waking up, it tries to enter a synchronized block, potentially moving to the "Blocked" state.
- It then calls
wait()
, moving to the "Waiting" state. - Finally, it completes execution and moves to the "Terminated" state.
Exercises
Exercise 1: Thread States
Create a Java program that demonstrates the transition of a thread through all the states: New, Runnable, Blocked, Waiting, Timed Waiting, and Terminated.
Solution:
public class ThreadStateDemo { public static void main(String[] args) { Object lock = new Object(); Thread thread = new Thread(() -> { try { System.out.println("Thread is in Runnable state"); Thread.sleep(500); // Timed Waiting state synchronized (lock) { System.out.println("Thread is in Blocked state"); lock.wait(); // Waiting state } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread is in Terminated state"); }); System.out.println("Thread is in New state"); thread.start(); try { Thread.sleep(100); // Ensure the thread enters Timed Waiting state synchronized (lock) { lock.notify(); // Move thread from Waiting to Runnable state } } catch (InterruptedException e) { e.printStackTrace(); } } }
Exercise 2: Thread Lifecycle Monitoring
Write a Java program that monitors and prints the state of a thread at regular intervals until it terminates.
Solution:
public class ThreadLifecycleMonitor { public static void main(String[] args) { Thread thread = new Thread(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.start(); while (thread.getState() != Thread.State.TERMINATED) { System.out.println("Thread state: " + thread.getState()); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Thread state: " + thread.getState()); } }
Conclusion
Understanding the thread lifecycle is essential for effective multithreading in Java. By knowing the different states a thread can be in and how to manage transitions between these states, you can write more efficient and robust multithreaded applications. In the next section, we will explore synchronization mechanisms to manage thread interactions safely.
Java Programming Course
Module 1: Introduction to Java
- Introduction to Java
- Setting Up the Development Environment
- Basic Syntax and Structure
- Variables and Data Types
- Operators
Module 2: Control Flow
Module 3: Object-Oriented Programming
- Introduction to OOP
- Classes and Objects
- Methods
- Constructors
- Inheritance
- Polymorphism
- Encapsulation
- Abstraction
Module 4: Advanced Object-Oriented Programming
Module 5: Data Structures and Collections
Module 6: Exception Handling
Module 7: File I/O
Module 8: Multithreading and Concurrency
- Introduction to Multithreading
- Creating Threads
- Thread Lifecycle
- Synchronization
- Concurrency Utilities
Module 9: Networking
- Introduction to Networking
- Sockets
- ServerSocket
- DatagramSocket and DatagramPacket
- URL and HttpURLConnection