Java Programming Thread Lifecycle And Thread Class Complete Guide
Understanding the Core Concepts of Java Programming Thread Lifecycle and Thread Class
Java Programming: Thread Lifecycle and Thread Class
New State: When a thread object is created using the
new
keyword but has not yet started running, it is in the new state.Thread t = new Thread();
Runnable State: A thread moves into the runnable state after calling the
start()
method on it. In this state, the thread is ready to run and waits for the thread scheduler to allocate CPU time.Thread t = new Thread(); t.start(); // now thread moves into runnable state
Blocked State: If the thread is trying to enter a synchronized block or method but cannot do so because another thread holds the lock, it enters the blocked state.
synchronized (lock) { // critical section code }
Waiting State: A thread enters the waiting state when it expects to be notified by another thread to proceed. Methods like
wait()
,join()
, andsleep()
can lead to this state.obj.wait(); // causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
Timed Waiting State: Similar to the waiting state, but the thread will stay in this state for a certain period or until notified. Methods that can cause a thread to be in timed waiting are
sleep(long millis)
,wait(long timeout)
,join(long millis)
, etc.Thread.sleep(2000); // causes the current thread to pause execution for 2000 milliseconds
Terminated State: This is the final state of a thread's life. Once a thread completes its execution or returns from
run()
method, it is in the terminated state.public void run() { // thread logic here System.out.println("Thread execution completed."); // once all code in run() is executed, thread becomes terminated }
Thread Class in Java
The Thread
class in Java is a fundamental part of concurrency as it provides methods to control the execution of threads and manage their states.
Constructors:
Thread()
: Creates a new thread with default priority and no specified name.Thread(Runnable r)
: Creates a new thread where therun()
method is delegated to theRunnable
parameter.Thread(Runnable r, String name)
: Same as above but also sets the thread name.Thread(String name)
: Creates a new thread with a specific name.
Common Methods:
void start()
: Starts the thread in a separate call stack; internally calls therun()
method.void run()
: Contains the code to be executed by the thread.static void sleep(long millis)
: Causes the current thread to pause execution for a specified number of milliseconds. Can throwInterruptedException
.void join()
: Makes the calling thread wait for the thread represented bythis
to complete.void interrupt()
: Interrupts the thread on which it is called.boolean isInterrupted()
: Tests whether the thread has been interrupted.static boolean interrupted()
: Returns a boolean indicating the interrupted status of the thread.boolean isAlive()
: Returns a boolean indicating if the thread represented bythis
is still alive.int getPriority()
: Returns the priority of this thread.void setPriority(int pri)
: Changes the priority of the thread.String getName()
: Returns the name of the thread.void setName(String Name)
: Changes the name of the thread.Thread.State getState()
: Returns the current state of the thread.
Synchronization Related Methods:
void wait()
: Causes the current thread to wait until another thread calls thenotify()
ornotifyAll()
method for this thread’s monitor object.void notify()
: Wakes up a single thread that is waiting on this thread's monitor object.void notifyAll()
: Wakes up all the threads that are waiting on this thread's monitor object.
Thread Priority Levels:
MIN_PRIORITY
: The minimum priority value assigned to a thread.NORM_PRIORITY
: Default priority assigned to a thread.MAX_PRIORITY
: Maximum priority a thread can have.
Setting thread priority can be done using
setPriority()
:Thread t = new Thread(); t.setPriority(Thread.MAX_PRIORITY);
Daemon Threads: Daemon threads are service provider threads that run in the background and provide services to the user threads. They have a lower priority than user threads. JVM terminates all daemon threads when all user threads are dead.
Thread t = new Thread(); t.setDaemon(true);
Thread Groups: Threads can belong to thread groups which make it easier to control the multiple threads at once.
ThreadGroup group = new ThreadGroup("MyGroup"); Thread t = new Thread(group, myRunnable, "thread-1", stackSize);
Important Concepts
Thread Context Switching: The process where the CPU changes the context of one thread to another. This involves saving the state of current thread and loading the saved state of another thread.
Deadlock: Situation in multithreading where two or more threads are blocked forever, each waiting on the other.
Liveness Issues: These are problems related to the performance and responsiveness of applications. Deadlocks, race conditions, starvevation, and livelocks fall under this category.
Race Conditions: Occurs when two or more threads can access shared data and they try to change it at the same time. As a result, behavior of the program is unpredictable.
Thread Interference: Happens when two threads perform operations on the shared resource concurrently.
Thread Safety: Code or objects that operate correctly when used concurrently.
Atomic Operations: Operations that cannot be interrupted or subdivided into smaller steps once they have begun execution. Java provides
AtomicInteger
,AtomicLong
, etc. classes to handle such operations safely.Volatile Keyword: Indicates that a variable may be changed unpredictably by other parts of your program, usually by another thread. Variables declared using
volatile
are visible to all threads.Example of
volatile
usage:public class Counter { private volatile int count = 0; public int getCount() { return count; } public void increment() { count++; } }
Synchronized Blocks and Methods: These are blocks of code marked with a synchronized keyword that allow only one thread at a time to execute within them.
Synchronized method example:
public synchronized void incrementCount() { count++; }
Synchronized block example:
public void incrementCount() { synchronized(this) { count++; } }
Executor Framework: A high-level threading framework providing tools for managing and controlling threads, thread pools.
Example of Executor Service:
ExecutorService executor = Executors.newFixedThreadPool(10); executor.execute(new Runnable() { public void run() { // task code here } });
ThreadLocal Variables: These variables differ from their normal counterparts in that each thread that accesses one will have its own, independently initialized copy of the variable.
Online Code run
Step-by-Step Guide: How to Implement Java Programming Thread Lifecycle and Thread Class
Step 1: Introduction to Threads
A thread in Java is a sequence of instructions within a program that can be executed concurrently with other threads. Java has a built-in Thread
class which you can use or extend to create your own threads.
Step 2: Creating Threads
You can create threads in Java using two methods:
- Extending the
Thread
class: This involves creating a subclass ofThread
and overriding itsrun()
method. - Implementing the
Runnable
interface: This involves creating a class that implementsRunnable
and overrides itsrun()
method.
Example 1: Extending the Thread
class
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is running.");
}
}
public class Main {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
}
}
In this example:
MyThread
extends theThread
class and overrides therun()
method.- In the
Main
class, we create an instance ofMyThread
and call itsstart()
method to begin execution.
Example 2: Implementing the Runnable
interface
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Thread is running.");
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
In this example:
MyRunnable
implements theRunnable
interface and overrides therun()
method.- We create a
Thread
object, passing it an instance ofMyRunnable
. Then call thestart()
method on theThread
object to start the execution.
Step 3: Thread Lifecycle
Threads in Java go through several states during their lifetime:
- New: A thread is in this state when it is created but not yet started.
- Runnable: A thread is in this state as soon as you call the
start()
method on it. It might be running or waiting for CPU cycles to execute. - Blocked: The thread is in this state if it tries to enter a synchronized block/method but other threads are already inside it.
- Waiting: The thread enters this state by calling methods like
wait()
,join()
, orsleep(long)
with a non-zero argument. - Timed Waiting: The thread enters this state by calling methods like
sleep(long)
,join(long)
,wait(long)
. - Terminated: The thread is in this state after the
run()
method has completed.
Let’s take a look at some examples demonstrating different states.
Example 3: Using sleep()
public class SleepExample extends Thread {
public void run() {
try {
System.out.println("Thread is going to sleep for 5000 ms");
Thread.sleep(5000);
System.out.println("Thread is awake");
} catch (InterruptedException e) {
System.out.println(e.toString());
}
}
public static void main(String[] args) {
SleepExample t = new SleepExample();
System.out.println("State before starting thread: " + t.getState()); //NEW
t.start();
System.out.println("State after starting thread: " + t.getState()); //RUNNABLE
while (t.isAlive()) {
System.out.println("Thread is still running"); //TIMED_WAITING
try {
Thread.sleep(1000); // Sleep for 1 sec
} catch (InterruptedException e) {
System.out.println(e.toString());
}
}
System.out.println("State when thread is completed: " + t.getState()); //TERMINATED
}
}
Explanation:
- Before starting the thread, it's in the
NEW
state. - After calling
start()
, it transitions into theRUNNABLE
state. - When the thread calls
Thread.sleep()
, it enters theTIMED_WAITING
state. - After waking up from sleep and completing the
run()
method, the thread is in theTERMINATED
state.
Step 4: Joining Threads
The join()
method allows one thread to wait for the completion of another thread.
Example 4: Using join()
public class JoinExample extends Thread {
public void run() {
System.out.println(Thread.currentThread().getName() + " is running");
}
public static void main(String[] args) {
Thread t1 = new JoinExample();
Thread t2 = new JoinExample();
t1.start();
try {
// Main thread will wait for t1 to complete
t1.join();
} catch (InterruptedException e) {
System.out.println(e.toString());
}
t2.start();
}
}
Explanation:
t1
starts first and runs itsrun()
method.- The main thread waits for
t1
to complete usingt1.join()
. - Only after
t1
finishes,t2
is allowed to start.
Step 5: Synchronizing Threads
Sometimes, you need to synchronize threads to avoid race conditions. One way to do this in Java is by using the synchronized
keyword.
Example 5: Synchronized Threads
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class SyncExample extends Thread {
private Counter counter;
public SyncExample(Counter counter) {
this.counter = counter;
}
public void run() {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
}
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
SyncExample t1 = new SyncExample(counter);
SyncExample t2 = new SyncExample(counter);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Count: " + counter.getCount());
}
}
Explanation:
Counter.increment()
is synchronized so that only one thread can access it at a time.- Both
t1
andt2
increment the counter 1000 times. - The main thread waits for both
t1
andt2
to complete by callingjoin()
on them. - Without synchronization, the final count might be less than 2000 due to race conditions. With synchronization, it ensures that the final count is exactly 2000.
Summary
- New: Thread is created but hasn't been started.
- Runnable: Thread has started and can be scheduled for execution by the JVM.
- Blocked/Waiting/Timed Waiting: States where a thread is not allowed to execute.
- Terminated: After the
run()
method completes.
Additional Tips
- Use
Thread.sleep(ms)
method to pause the current thread for the specified milliseconds. - Use
Thread.join()
to make the main thread wait until another thread completes its execution. - Use
synchronized
blocks/methods to control access to critical sections of code.
Top 10 Interview Questions & Answers on Java Programming Thread Lifecycle and Thread Class
1. What are the states of a thread in Java?
- Answer: In Java, a thread's lifecycle consists of the following states:
- New: A thread is in this state when an object of type
Thread
is created but thestart()
method is not yet called on that thread. - Runnable: Once the
start()
method is called on the thread object, it moves to this state. While in this state, the thread may be running (executing itsrun()
method) or waiting for CPU allocation (ready to run). - Blocked: A thread is in this state when it is waiting to acquire a lock on an object to enter a synchronized block or method.
- Waiting: This state is reached when a thread calls methods like
Object.wait()
,Thread.join()
, orLockSupport.park()
, causing it to sleep indefinitely until another thread wakes it up. - Timed Waiting: This state is reached when a thread calls methods like
Object.wait(long timeout)
,Thread.join(long millis)
,Thread.sleep(long millis)
, orLockSupport.parkNanos(long nanos)
for a specified time. - Terminated: A thread is in this state when the
run()
method completes (finishes execution).
- New: A thread is in this state when an object of type
2. What is the purpose of the Thread
class in Java?
- Answer: The
Thread
class in Java is used to create and manage threads. It encapsulates thread behaviors, such as priority, name, and its state. TheThread
class contains methods to control thread execution, likestart()
,stop()
,join()
,sleep()
, etc. Extending theThread
class allows you to define a new thread's behavior by overriding therun()
method.
3. What is the difference between start()
and run()
methods of Thread class?
- Answer: The
start()
andrun()
methods are both used in theThread
class, but they serve different purposes:start()
: This method is called to request the JVM to schedule the thread for execution. Internally, it calls therun()
method of the thread (or theRunnable
'srun()
method, if the thread was created by implementingRunnable
). Oncestart()
is called, the thread moves to the Runnable state and the JVM invokes therun()
method on the thread.run()
: This method contains code that defines the task of the thread. If you override this method, you must explicitly callsuper.run()
to ensure that the thread executes properly, unless you intend to replace the entire behavior of the thread with your custom implementation.
4. Can a thread be started multiple times in Java?
- Answer: No, a thread can be started only once. Invoking the
start()
method on a thread that is already in the Runnable state or has already terminated will throw anIllegalThreadStateException
. Once a thread finishes its execution, it cannot be started again; instead, a new thread instance must be created and started.
5. How can one stop a thread in Java?
- Answer: There are a few ways to stop a thread in Java, but it’s generally discouraged to abruptly terminate threads due to potential resource leakage and inconsistent state. Recommended practices are:
- Using a Flag (Volatility): Set a boolean flag (often
volatile
) that the thread checks periodically to decide whether to terminate. - Interruption: The
interrupt()
method sets the thread’s interrupt status. Threads can then check this status and exit gracefully. - Avoiding
Thread.stop()
: Thestop()
method is deprecated and shouldn’t be used because it can cause inconsistent states and locks can’t be released safely.
- Using a Flag (Volatility): Set a boolean flag (often
6. What does the join()
method do in Java?
- Answer: The
join()
method is used to wait for a thread to terminate. There are three overloaded forms ofjoin()
:join()
: Waits indefinitely for the thread to die.join(long mills)
: Waits at mostmills
milliseconds for the thread to die.join(long mills, int nanos)
: Waits at mostmills
milliseconds plusnanos
nanoseconds for the thread to die.- This is useful when a thread needs to wait for one or more other threads to finish before it continues its execution.
7. Explain how to set and get the thread priority in Java?
- Answer: In Java, thread priority can be set and checked using the
setPriority()
andgetPriority()
methods respectively:- Set Priority: You can set the priority of a thread using
setPriority(int newPriority)
, wherenewPriority
can range fromThread.MIN_PRIORITY
(1) toThread.MAX_PRIORITY
(10).Thread.NORM_PRIORITY
is the default priority (5). - Get Priority: The
getPriority()
method returns the thread’s current priority. - It’s important to note that thread priority is only a hint to the thread scheduler, and it is up to the JVM to determine scheduling.
- Set Priority: You can set the priority of a thread using
8. What is the difference between daemon and user threads in Java?
- Answer: In Java, threads can be classified into two types: daemon and user (non-daemon) threads.
- User Threads: These are threads that are typically created and controlled by the program. The JVM waits for all non-daemon threads to terminate before itself shutting down.
- Daemon Threads: These are service-provider threads that run in the background to perform tasks such as garbage collection. Daemon threads don’t prevent the JVM from exiting if all user threads finish. If all remaining threads are daemon threads, the JVM exits.
- You can set a thread as a daemon using
setDaemon(true)
before starting the thread. Daemon threads do not inherit daemon status from parent threads.
9. How to handle multiple threads synchronization in Java?
- Answer: Handling synchronization in Java involves ensuring that multiple threads can safely work on shared data without causing inconsistent states or race conditions. Common techniques include:
- Synchronized Methods: Declaring a method
synchronized
ensures that only one thread can execute the method at a time on a given instance. - Synchronized Blocks: If only a part of the method needs to be synchronized, use synchronized blocks.
- Lock Interface (
java.util.concurrent.locks.Lock
): Provides more flexible locking mechanisms than synchronized methods, such astryLock()
, which allows thread to check if a lock is available without waiting. - ReentrantLock: A reentrant mutual exclusion
Lock
with the same basic behavior and semantics as the implicit monitor lock accessed usingsynchronized
methods and statements. It differs from synchronized in that it is more flexible; a thread can hold a lock any number of times. - Volatile Keyword: This keyword ensures that changes made by one thread to a volatile variable are visible to all other threads.
- Synchronized Methods: Declaring a method
10. What is the meaning of thread deadlock in Java, and how can it be avoided?
- Answer: Thread deadlock is a situation in multi-threaded programming where two or more threads are blocked forever because each is waiting for the other to release a resource. Deadlocks happen when the following four conditions (known as the necessary conditions for deadlock) are met:
- Mutual Exclusion: Only one thread can occupy a resource at a time.
- Hold and Wait: A thread holding at least one resource is waiting to acquire additional resources held by other threads.
- No Preemption: Resources cannot be forcibly taken from a thread, they must be released voluntarily.
- Circular Wait: A circular wait involves two or more threads waiting on each other in a circular chain, where each thread is waiting for another to release a resource.
Avoiding Deadlock: Some strategies to prevent deadlock are: - Breaking the Circular Wait condition by assigning a global order to resources, and requiring threads to obtain resources only in increasing order. - Breaking the Hold and Wait condition by not allowing threads to hold on to multiple resources at once; they must request all required resources at once. - Breaking the No Preemption condition by forcibly removing resources from held threads. - Breaking the Mutual Exclusion condition by using non-exclusive locks wherever possible.
Login to post a comment.