0% found this document useful (0 votes)
3 views

thread notes

The document outlines the life cycle of threads in Java, detailing states such as New, Runnable, Blocked, Waiting, Timed Waiting, and Terminated. It also discusses important thread methods, common exceptions related to threads, and the concept of thread priority and synchronization. Key points include the need for synchronization to prevent data corruption and race conditions in a multithreaded environment.

Uploaded by

alamk765432
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

thread notes

The document outlines the life cycle of threads in Java, detailing states such as New, Runnable, Blocked, Waiting, Timed Waiting, and Terminated. It also discusses important thread methods, common exceptions related to threads, and the concept of thread priority and synchronization. Key points include the need for synchronization to prevent data corruption and race conditions in a multithreaded environment.

Uploaded by

alamk765432
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 28

Life cycle of thread :

The life cycle consists of various stages, and understanding these stages helps in
creating efficient multi-threaded programs.

Thread Life Cycle Stages


New (Born): A thread is in the new state when it is created but not yet started.
This is the initial state of a thread.
Runnable: A thread moves to the runnable state when the start() method is called.
In this state, the thread is ready to run, but it may not be running at the moment
because the CPU might be allocating resources to other threads.
Blocked: A thread moves to the blocked state when it is waiting for some resource
(e.g., a lock) to be released by another thread.
Waiting: A thread is in the waiting state when it is waiting indefinitely for another
thread to perform a particular action (such as a join() or notify()).
Timed Waiting: A thread is in the timed waiting state when it is waiting for a
specified period of time (such as using sleep(), join(time), etc.).
Terminated (Dead): A thread is in the terminated state when it has completed its
execution or has been terminated due to an exception.
Example Code:
Below is a simple Java program that demonstrates the different states of a thread:
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread started, entering runnable
state");

try {
// Timed Waiting State: Thread will sleep for 3
seconds
Thread.sleep(3000);

Prepared by Shaikh Basharat


System.out.println("Thread woke up after sleeping
for 3 seconds");
} catch (InterruptedException e) {
System.out.println("Thread interrupted");
}

System.out.println("Thread is in the running state after


sleep");

// End of run() method, thread terminates and goes to


the dead state
}
}

public class ThreadLifeCycleDemo {


public static void main(String[] args) {
System.out.println("Main thread starts");

MyThread myThread = new MyThread();

// New State: Thread is created but not yet started


System.out.println("Thread created, but not yet
started");

myThread.start(); // Transition to Runnable state

try {
// Main thread waits for myThread to complete
myThread.join(); // Waiting for myThread to finish,
makes main thread enter waiting state

Prepared by Shaikh Basharat


} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("Main thread ends");


}
}

Thread method :
a Thread is a unit of execution, and the Thread class provides various methods to
control and manage the behavior of threads. Here are some important Thread
methods in Java that you can use to work with threads:

Common Thread Methods:


start():
This method is used to begin the execution of a thread. It causes the thread to enter
the runnable state. You must call start() to invoke the run() method of a thread.
Thread t = new Thread();
t.start(); // Starts the thread

run():
The run() method contains the code to be executed by the thread. You override this
method to define what the thread does. The run() method is executed automatically
when you call start() on a thread.

public void run() {


// Code to be executed in the thread
}

Prepared by Shaikh Basharat


sleep(long millis):
This static method pauses the execution of the current thread for the specified
amount of time (in milliseconds). It throws InterruptedException if another thread
interrupts it while sleeping.
try {
Thread.sleep(2000); // Sleep for 2 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}

join():
This method is used to pause the execution of the current thread until the thread on
which join() was called has finished executing. It can also accept a timeout to
specify how long to wait.
Thread t1 = new Thread();
t1.start();
t1.join(); // Current thread will wait for t1 to complete

interrupt():
This method interrupts a thread that is currently sleeping, waiting, or running. If a
thread is sleeping or waiting, it will throw an InterruptedException.
thread.interrupt(); // Interrupts the thread

isAlive():
This method checks whether a thread is still alive (i.e., if it has been started but not
yet finished).

Prepared by Shaikh Basharat


boolean alive = thread.isAlive(); // Returns true if the thread is alive

getName():
This method returns the name of the thread.
String threadName = thread.getName(); // Get the name of the
thread

setName(String name):
This method sets the name of the thread.
thread.setName("MyThread"); // Set the name of the thread

setPriority(int priority):
This method sets the priority of the thread. The priority should be an integer value
between Thread.MIN_PRIORITY (1) and Thread.MAX_PRIORITY (10), with the
default being Thread.NORM_PRIORITY (5).
thread.setPriority(Thread.MAX_PRIORITY); // Set maximum priority

getPriority():
This method returns the current priority of the thread.
int priority = thread.getPriority(); // Get the current priority of the
thread

yield():
This static method causes the current thread to yield (temporarily pause) its
execution, allowing other threads of the same priority to execute.

Prepared by Shaikh Basharat


Thread.yield(); // Yield execution to other threads of the same
priority

currentThread():
This static method returns a reference to the currently executing thread.
Thread current = Thread.currentThread(); // Get the current thread

getId():
This method returns the unique ID of the thread.
long threadId = thread.getId(); // Get the ID of the thread

example code –

class MyThread extends Thread {


public void run() {
System.out.println("Thread " + getName() + " started.");

try {
Thread.sleep(2000); // Sleep for 2 seconds
System.out.println("Thread " + getName() + " woke
up.");
} catch (InterruptedException e) {
System.out.println("Thread " + getName() + " was
interrupted.");
}

System.out.println("Thread " + getName() + "


finished.");

Prepared by Shaikh Basharat


}
}

public class ThreadMethodsExample {


public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();

t1.setName("Thread-1");
t2.setName("Thread-2");

t1.start(); // Start t1
t2.start(); // Start t2

try {
t1.join(); // Wait for t1 to finish
t2.join(); // Wait for t2 to finish
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("Main thread ends.");


}
}

Prepared by Shaikh Basharat


Thread exception :
exceptions related to threads are typically associated with certain actions a thread
performs, such as interrupting, waiting, or sleeping. The most common exceptions
you’ll encounter while working with threads are:

1. InterruptedException

 This exception occurs when a thread is interrupted while it is sleeping,


waiting, or otherwise blocked.
 For example, if a thread is sleeping or waiting for a lock and another thread
interrupts it, the interrupted thread will throw an InterruptedException.

Common Methods that throw InterruptedException:

 Thread.sleep(long millis)
 Object.wait()
 Thread.join()
 Thread.yield() (in some cases)

Ex –
class MyThread extends Thread {

public void run() {

try {

// Sleep for 5 seconds

Thread.sleep(5000);

System.out.println("Thread completed.");

} catch (InterruptedException e) {

System.out.println("Thread was interrupted during


sleep.");

Prepared by Shaikh Basharat


public class ThreadExceptionExample {

public static void main(String[] args) {

MyThread t = new MyThread();

t.start();

// Interrupt the thread after 2 seconds

try {

Thread.sleep(2000);

t.interrupt(); // Interrupt the thread while it's


sleeping

} catch (InterruptedException e) {

e.printStackTrace();

Output:

Thread was interrupted during sleep.

2. IllegalThreadStateException

 This exception occurs when an illegal operation is performed on a thread,


such as starting a thread that has already been started or stopping a thread
that has already been terminated.

Example:

public class IllegalThreadStateExceptionExample {


public static void main(String[] args) {

Prepared by Shaikh Basharat


Thread t = new Thread(() -> {
System.out.println("Thread is running");
});

t.start(); // Start the thread

// Trying to start the thread again will throw


IllegalThreadStateException
try {
t.start(); // This will throw
IllegalThreadStateException
} catch (IllegalThreadStateException e) {
System.out.println("Caught exception: " + e);
}
}
}

Explanation:

 The t thread is started, and then the start() method is called again on the
same thread, which throws an IllegalThreadStateException.

Output:
Thread is running
Caught exception: java.lang.IllegalThreadStateException: Thread
already started.

3. NullPointerException (in Thread Operations)

 A NullPointerException can occur if you attempt to perform thread


operations on a null thread object.

Example:public class NullPointerThreadExample {


public static void main(String[] args) {
Thread t = null;
try {
t.start(); // Attempting to start a null thread
will cause NullPointerException
} catch (NullPointerException e) {
System.out.println("Caught exception: " + e);
}
}

Prepared by Shaikh Basharat


}

Explanation:

 The thread t is null, and calling t.start() causes a


NullPointerException because there’s no valid thread object.

Output:
Caught exception: java.lang.NullPointerException

4. RejectedExecutionException (in Thread Pool)

 This exception occurs in thread pools (such as ExecutorService)


when a task cannot be executed. It may be thrown when the task queue is
full or when the executor has been shut down and cannot accept any more
tasks.

Example:
import java.util.concurrent.*;

public class RejectedExecutionExceptionExample {


public static void main(String[] args) {
ExecutorService executor =
Executors.newFixedThreadPool(1);

// Submit a task to the executor


executor.submit(() -> {
System.out.println("Task 1 is running");
});

executor.submit(() -> {
System.out.println("Task 2 is running");
}); // This will be rejected as the thread pool size is
1

executor.shutdown(); // Shutdown the executor


try {
executor.submit(() -> System.out.println("Task 3"));
// This will throw RejectedExecutionException
} catch (RejectedExecutionException e) {
System.out.println("Caught exception: " + e);
}

Prepared by Shaikh Basharat


}
}

Explanation:

 In the example, the ExecutorService is created with only one thread in


the pool. The second task is rejected because the pool is full and cannot
accept any more tasks.
 After shutting down the executor, attempting to submit another task causes a
RejectedExecutionException.

Output:
arduino
Copy
Task 1 is running
Task 2 is running
Caught exception:
java.util.concurrent.RejectedExecutionException: Task already
completed

5. SecurityException

 This exception occurs when a security manager denies access to the thread,
for example, when a thread is trying to modify the system properties or
access restricted resources.

Example:
public class SecurityExceptionExample {
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.setProperty("user.name", "newuser"); //
Modifying system properties
});

try {
t.start();
} catch (SecurityException e) {
System.out.println("Caught exception: " + e);
}
}
}

Prepared by Shaikh Basharat


Explanation:

 If a security manager is present and restricts modifying system properties,


calling System.setProperty() will throw a SecurityException.

Output:
Caught exception: java.lang.SecurityException: Unable to modify
system properties

How to Handle Exceptions in Threads

You can handle exceptions in threads using standard try-catch blocks. If the thread
is performing some potentially risky operation, catch the specific exception type
and handle it appropriately.

 For InterruptedException: Always use a try-catch block around methods


like sleep(), join(), and wait() to handle interruptions.

 For IllegalThreadStateException: Ensure you don’t call start() on a thread


that has already been started.

 For NullPointerException: Ensure that the thread object is initialized before


invoking methods like start() or join().

Thread Priority in Java

In Java, each thread has a priority that helps the thread scheduler determine the
order in which
threads should be executed. Thread priority is an integer value that ranges from 1
to 10:

• MIN_PRIORITY: 1 (lowest priority)


• NORM_PRIORITY: 5 (default priority)
• MAX_PRIORITY: 10 (highest priority)

Prepared by Shaikh Basharat


Threads with higher priority are more likely to be executed before threads with
lower priority, but this is not guaranteed. The actual execution order depends on
the JVM and the underlying operating system's thread scheduling algorithm.

Methods for Setting and Getting Thread Priority

1. setPriority(int newPriority)
o Purpose: Sets the priority of a thread.
o Usage Example:
Thread t = new Thread();
t.setPriority(Thread.MAX_PRIORITY); // Sets the priority to 10

2. getPriority()
o Purpose: Returns the current priority of the thread.
o Usage Example:
int priority = t.getPriority();
System.out.println("Thread Priority: " + priority);

Example: Setting and Getting Thread Priority

public class ThreadPriorityExample extends Thread {


public void run() {
System.out.println("Running thread: " +
Thread.currentThread().getName());
System.out.println("Thread priority: " +
Thread.currentThread().getPriority());
}
public static void main(String[] args) {
ThreadPriorityExample t1 = new
ThreadPriorityExample();
ThreadPriorityExample t2 = new
ThreadPriorityExample();
t1.setPriority(Thread.MIN_PRIORITY); // Priority 1
t2.setPriority(Thread.MAX_PRIORITY); // Priority 10
t1.start();
t2.start();
}
}

Prepared by Shaikh Basharat


Output (may vary):

Running thread: Thread-1


Thread priority: 10
Running thread: Thread-0
Thread priority: 1

Key Points to Remember:


• By default, a thread inherits the priority of the thread that created it.

• Setting a thread’s priority to a value outside the range (1 to 10) will throw an
IllegalArgumentException.

• Thread priority does not guarantee execution order due to platform-dependent


thread scheduling.

Synchronization
In Java, synchronization is a mechanism used to control access to shared resources
by multiple threads in a concurrent environment. It ensures that only one thread
can access the shared resource at a time, preventing issues such as data corruption,
race conditions, and inconsistent results.
Why Synchronization is Needed:
In a multithreaded environment, multiple threads may try to access and modify the
same shared resource simultaneously. If threads are allowed to access the resource
at the same time, it can lead to race conditions and inconsistent data.
Synchronization is a way to avoid this problem by ensuring that only one thread
can access the resource at a time.
Key Concepts of Synchronization:
1. Critical Section: The code that accesses and modifies shared resources.
When one thread enters the critical section, other threads must wait until it
exits.
2. Race Condition: A situation where the output of a program depends on the
sequence or timing of other uncontrollable events (such as threads' execution
order). This often leads to inconsistent results.

Prepared by Shaikh Basharat


3. Mutual Exclusion (Mutex): A property that ensures only one thread can
access a critical section at a time.
4. Deadlock: A situation in which two or more threads are blocked forever,
each waiting for the other to release a resource.

Ways to Achieve Synchronization in Java:


1. Synchronized Methods
2. Synchronized Blocks
3. Reentrant Locks (Java 5 and onwards)
4. The volatile Keyword
5. Atomic Variables
1. Synchronized Methods
You can make an entire method synchronized using the synchronized keyword.
When a method is synchronized, only one thread can execute that method on
the same object at a time. Other threads will be blocked until the first thread
completes its execution.
Syntax:
java
Copy
synchronized returnType methodName() {
// critical section
}
Example:
java
Copy
class Counter {
private int count = 0;

Prepared by Shaikh Basharat


// Synchronized method to ensure only one thread can access it at a time
synchronized void increment() {
count++;
}

synchronized int getCount() {


return count;
}
}

public class SynchronizationExample {


public static void main(String[] args) {
Counter counter = new Counter();

// Thread 1
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});

// Thread 2
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {

Prepared by Shaikh Basharat


counter.increment();
}
});

// Start threads
t1.start();
t2.start();

// Wait for threads to finish


try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

// Output the result


System.out.println("Final count: " + counter.getCount());
}
}
Explanation:
 The increment() and getCount() methods are synchronized, ensuring that
only one thread can access these methods at a time for the same object
(counter).
 Without synchronization, both threads could modify count concurrently,
leading to incorrect results.

Prepared by Shaikh Basharat


Output (with synchronization):
yaml
Copy
Final count: 2000

2. Synchronized Blocks
Instead of synchronizing the entire method, you can synchronize a block of
code within a method. This is useful if only part of the method needs
synchronization, improving performance by reducing contention.
Syntax:
java
Copy
synchronized(object) {
// critical section
}
Example:
java
Copy
class Counter {
private int count = 0;

void increment() {
synchronized(this) {
count++;
}

Prepared by Shaikh Basharat


}

int getCount() {
synchronized(this) {
return count;
}
}
}

public class SynchronizationBlockExample {


public static void main(String[] args) {
Counter counter = new Counter();

// Thread 1
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});

// Thread 2
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}

Prepared by Shaikh Basharat


});

// Start threads
t1.start();
t2.start();

// Wait for threads to finish


try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

// Output the result


System.out.println("Final count: " + counter.getCount());
}
}
Explanation:
 The synchronized(this) block ensures that only one thread can modify or
read the count variable at any time. The this refers to the current object
(counter).

3. Reentrant Locks (Java 5 and onwards)


Java provides the ReentrantLock class as part of the java.util.concurrent.locks
package. It provides more flexibility than synchronized methods and blocks,

Prepared by Shaikh Basharat


such as trying to acquire a lock without blocking indefinitely and setting a
timeout.
Example:
java
Copy
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Counter {
private int count = 0;
private Lock lock = new ReentrantLock(); // ReentrantLock instance

void increment() {
lock.lock(); // Acquire the lock
try {
count++;
} finally {
lock.unlock(); // Release the lock
}
}

int getCount() {
lock.lock();
try {
return count;

Prepared by Shaikh Basharat


} finally {
lock.unlock();
}
}
}

public class ReentrantLockExample {


public static void main(String[] args) {
Counter counter = new Counter();

// Thread 1
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});

// Thread 2
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});

// Start threads

Prepared by Shaikh Basharat


t1.start();
t2.start();

// Wait for threads to finish


try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

// Output the result


System.out.println("Final count: " + counter.getCount());
}
}
Explanation:
 ReentrantLock provides explicit locking and unlocking. It allows more
flexibility and can be used for advanced use cases, like try-lock, timed
locks, and interruptible locks.

4. volatile Keyword
The volatile keyword in Java ensures that updates to a variable are immediately
visible to all threads. While it doesn't prevent race conditions or provide
atomicity like synchronization, it guarantees visibility.
Example:
java

Prepared by Shaikh Basharat


Copy
class Counter {
private volatile int count = 0;

void increment() {
count++;
}

int getCount() {
return count;
}
}

public class VolatileExample {


public static void main(String[] args) {
Counter counter = new Counter();

// Thread 1
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});

// Thread 2

Prepared by Shaikh Basharat


Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});

// Start threads
t1.start();
t2.start();

// Wait for threads to finish


try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

// Output the result


System.out.println("Final count: " + counter.getCount());
}
}
Explanation:

Prepared by Shaikh Basharat


 The volatile keyword ensures that the count variable's value is consistently
updated and visible to all threads. However, it doesn't guarantee atomicity,
so it can still lead to issues if you need to perform complex operations.

5. Atomic Variables
Java provides a set of atomic variables in the java.util.concurrent.atomic
package (e.g., AtomicInteger, AtomicLong, etc.), which offer thread-safe
operations without the need for synchronization.
Example:
import java.util.concurrent.atomic.AtomicInteger;

class Counter {

private AtomicInteger count = new AtomicInteger(0);

void increment() {

count.incrementAndGet();

int getCount() {

return count.get();

public class AtomicExample {

public static void main(String[] args) {

Counter counter = new Counter();

// Thread 1

Thread t1 = new Thread(() -> {

Prepared by Shaikh Basharat


for (int i = 0; i < 1000; i++) {

counter.increment();

});

// Thread 2

Thread t2 = new Thread(() -> {

for (int i = 0; i < 1000; i++) {

counter.increment();

});

// Start threads

t1.start();

t2.start();

// Wait for threads to finish

try {

t1.join();

t2.join();

} catch (InterruptedException e) {

e.printStackTrace();

// Output the result

System.out.println("Final count: " + counter.getCount());

Prepared by Shaikh Basharat

You might also like