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

ognexception_threads

The document discusses Java exception handling, including multi-catch blocks, nested try-catch, finally blocks, and the throw and throws keywords. It explains how exceptions propagate through method calls and the rules for overriding methods with respect to exceptions. Additionally, it provides code examples to illustrate the concepts of exception handling in Java.
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)
4 views

ognexception_threads

The document discusses Java exception handling, including multi-catch blocks, nested try-catch, finally blocks, and the throw and throws keywords. It explains how exceptions propagate through method calls and the rules for overriding methods with respect to exceptions. Additionally, it provides code examples to illustrate the concepts of exception handling in Java.
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/ 131

Java Multi-catch block

• A try block can be followed by one or more catch blocks.


• Each catch block must contain a different exception handler.
Java Multi-catch block

•At a time only one exception occurs and at a time only one catch block
is executed.
•All catch blocks must be ordered from most specific to most general,
i.e. catch for ArithmeticException must come before catch for
Exception.
Java Multi-catch block
public class CatchTest
{
public static void main(String[] args)
{
try
{
int a[]=new int[5];
a[5]=30/1;
}
catch(ArithmeticException e)
{
System.out.println("Arithmetic Exception occurs");
}
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println("ArrayIndexOutOfBounds Exception occurs");
}
catch(Exception e)
{
System.out.println("Parent Exception occurs");
} O/P:
System.out.println("rest of the code"); ArrayIndexOutOfBounds Exception occurs
} rest of the code
}
public class CatchTest
{
public static void main(String[] args) try block contains two
{ exceptions. But at a time only
try{ one exception occurs and its
int a[]=new int[5]; corresponding catch block is
a[4]=30/0; executed.
System.out.println(a[10]);
}
catch(ArithmeticException e)
{
System.out.println("Arithmetic Exception
occurs");
}
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println("ArrayIndexOutOfBounds
Exception occurs");
}
catch(Exception e)
{
System.out.println("Parent Exception occurs"); Output:
} Arithmetic Exception occurs
System.out.println("rest of the code"); rest of the code
}}
public class Test we generate NullPointerException, but
{ didn't provide the corresponding
public static void main(String[] args) exception type. In such case, the catch
{ block containing the parent exception
try class Exception will invoked.
{
String s=null;
System.out.println(s.length());
}
catch(ArithmeticException e)
{
System.out.println("Arithmetic Exception occurs");
}
catch(ArrayIndexOutOfBoundsException e)
{
System.out.println("ArrayIndexOutOfBounds
Exception occurs");
}
catch(Exception e)
{
System.out.println("Parent Exception occurs"); O/P:
} Parent Exception occurs
System.out.println("rest of the code"); rest of the code
}}
class Test
{
public static void main(String args[]
{
try{
int a[]=new int[5];
a[5]=30/0;
} without maintaining the order of exceptions
catch(Exception e) (i.e. from most specific to most general).
{
System.out.println("common task
completed");
}
catch(ArithmeticException e)
{
System.out.println("task1 is
completed");
}
catch(ArrayIndexOutOfBoundsExceptio
n e)
{
System.out.println("task 2 completed"); Output:
} Compile-time error
System.out.println("rest of the code...");
}}
Nested try
When any try block does not have a catch block for a particular exception:-

• catch block of the outer (parent) try block are checked for that exception, and
if it matches, the catch block of outer try block is executed.

If none of the catch block specified in the code is unable to handle the exception:- -
--Java runtime system will handle the exception.

Then it displays the system generated message for that exception.


Nested try
public class NestedTryBlock
{ //catch block of inner try block 2
public static void main(String args[]) catch(ArrayIndexOutOfBoundsException e)
{ {
//outer try block System.out.println(e);
try{ }
//inner try block 1
try System.out.println("other statement");
{ }
System.out.println("going to divide by 0"); //catch block of outer try block
int b =39/0; catch(Exception e)
} {
//catch block of inner try block 1 System.out.println("handled the exception
catch(ArithmeticException e) (outer catch)");
{ }
System.out.println(e);
} System.out.println("normal flow..");
//inner try block 2 }
try }
{
int a[]=new int[5];
a[5]=4;
}
Finally block
Finally block
• Java finally block is always executed whether an
exception is handled or not.
• It contains all the necessary statements that need to be
printed regardless of the exception occurs or not.
• The finally block follows the try-catch block.
• It can be used to put "cleanup" code such as closing a
file, closing connection, etc.
• The important statements to be printed can be placed in
the finally block.
class TestFinallyBlock { No exception occurs
public static void main(String args[])
{
try{
//below code do not throw any exception
int data=25/5;
System.out.println(data);
}
//catch won't be executed
catch(NullPointerException e){
System.out.println(e);
}
//executed regardless of exception occurred or not
finally {
System.out.println("finally block is always executed");
}

System.out.println("rest of the code...");


}
}
public class TestFinallyBlock2{
public static void main(String args[])
{
Exception handled
try
{
System.out.println("Inside try block");

//below code throws divide by zero exception


int data=25/0;
System.out.println(data); \
}

//handles the Arithmetic Exception / Divide by zero exception
catch(ArithmeticException e){
System.out.println("Exception handled");
System.out.println(e);
}

//executes regardless of exception occured or not


finally
{
System.out.println("finally block is always executed");
}

System.out.println("rest of the code...");


}
}
public class TestFinallyBlock1{
public static void main(String args[]){

try
{
System.out.println("Inside the try block");
Exception not handled
//below code throws divide by zero exception
int data=25/0;
System.out.println(data);
}
//cannot handle Arithmetic type exception
//can only accept Null Pointer type exception
catch(NullPointerException e){
System.out.println(e);
}

//executes regardless of exception occured or not


finally {
System.out.println("finally block is always executed");
}

System.out.println("rest of the code...");


}
}
throw keyword

• The Java throw keyword is used to throw an


exception explicitly.
• We specify the exception object which is to be
thrown.
• The Exception has some message with it that
provides the error description.
• These exceptions may be related to user inputs,
server, etc.
• We can throw either checked or unchecked
exceptions in Java by throw keyword.
• It is mainly used to throw a custom exception.
throw keyword

The syntax of the Java throw keyword is given below.

throw new exception_class("error message");

For example of throw IOException.


throw new IOException("sorry device error");
public class TestThrow1
{
Throwing Unchecked Exception
//function to check if person is eligible to vote or not
public static void validate(int age)
{
if(age<18)
{
//throw Arithmetic exception if not eligible to vote
throw new ArithmeticException("Person is not eligible to vote");
}
else
{
System.out.println("Person is eligible to vote!!");
}
}
//main method
public static void main(String args[])
{
//calling the function
validate(13);
System.out.println("rest of the code...");
}
}
import java.io.*;
Throwing Checked Exception
public class TestThrow2
{
//function to check if person is eligible to vote or not
public static void method() throws FileNotFoundException {
FileReader file = new FileReader("C:\\Users\\Anurati\\Desktop\\abc.txt");
BufferedReader fileInput = new BufferedReader(file);
throw new FileNotFoundException();
}
//main method
public static void main(String args[])
{
try If we throw a checked exception using throw keyword, it is must to
{ handle the exception using catch block or the method must declare it
method(); using throws declaration.
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
System.out.println("rest of the code...");
}
}
// class represents user-defined exception
Throwing User-defined Exception
class MyException extends Exception
{
public MyException(String str)
{
// Calling constructor of parent Exception
super(str);
}
}
// Class that uses above MyException
public class TestThrow3
{
public static void main(String args[])
{
try
{
// throw an object of user defined exception
throw new MyException("This is user-defined exception");
}
catch (MyException me)
{
System.out.println("Caught the exception");
// Print the message from MyException object
System.out.println(me.getMessage());
}
}
}
Exception Propagation

Exception can be handled in any method in call stack


either in the main() method, p() method, n() method or
m() method.

An exception is first thrown from the top of the stack and if it is not caught, it
drops down the call stack to the previous method. If not caught there, the
exception again drops down to the previous method, and so on until they are
caught or until they reach the very bottom of the call stack. This is called
exception propagation.
class Test
{ In the above example exception occurs in the m()
void m() method where it is not handled, so it is
{ propagated to the previous n() method where it is
int data=50/0; not handled, again it is propagated to the p()
}
method where exception is handled.
void n()
{
m();
}
void p()
{
try{
n();
}catch(Exception e)
{
System.out.println("exception handled");
}
}
public static void main(String args[])
{
Test ob=new Test();
ob.p(); Output:
System.out.println("normal flow..."); exception handled
}
normal flow...
}
class Test Checked exceptions are not propagated
{
void m()
{
throw new java.io.IOException("device error");//checked exception
}
void n()
{
m();
}
void p()
{
try
{
n();
}
catch(Exception e)
{
System.out.println("exception handeled");
}
}
public static void main(String args[])
{
Test ob=new Test();
ob.p(); Output:
System.out.println("normal flow"); Compile Time Error
}
}
Java throws keyword
• The Java throws keyword is used to declare an exception.
• It gives an information to the programmer that there may occur an
exception.
• exception handling code to be provided so that the normal flow of
the program can be maintained.
• Exception Handling is mainly used to handle the checked
exceptions.
• checked exceptions can be propagated by throws keyword.

Syntax of Java throws


return_type method_name() throws exception_class_name{
//method code
}
import java.io.IOException;
class Test Checked exceptions can be propagated by
{ throws keyword.
void m()throws IOException
{
throw new IOException("device error");//checked exception
}
void n()throws IOException
{
m();
}
void p()
{
try
{
n();
}catch(Exception e)
{
System.out.println("exception handled");
}
}
public static void main(String args[]) Output:
{
Test ob=new Test(); exception handled
ob.p(); normal flow...
System.out.println("normal flow...");
}}
import java.io.*;
Handle Exception Using try-catch block
class A
{
void f()throws IOException
{
throw new IOException("device error");
}
}
public class Test
{
public static void main(String args[])
{
try
{
A m=new A();
m.f();
}
catch(Exception e)
{ Output:
System.out.println("exception handled");
} exception handled
System.out.println("normal flow..."); normal flow...
}
}
import java.io.*; exception does not occur
class A
{
void f()throws IOException
{
System.out.println("device operation performed");
}
}
class Test
{
public static void main(String args[])throws IOException
{//declare exception
A m=new A();
m.f();
System.out.println("normal flow...");
} Output:
}
device operation performed
normal flow...
If exception occurs In case we declare the exception and the
exception occurs, it will be thrown at
runtime because throws does not handle
the exception.

import java.io.*;
class A{
void f()throws IOException{
throw new IOException("device error");
}
}
class Test{
public static void main(String args[])throws IOException
{//declare exception
A m=new M();
m.f();
System.out.println("normal flow...");
}
}
public class TestThrow
{
public static void checkNum(int num)
{
if (num < 1)
{
throw new ArithmeticException("\nNumber is negative, cannot calculate square");
}
else
{
System.out.println("Square of " + num + " is " + (num*num));
}
}
//main method
public static void main(String[] args) {
TestThrow obj = new TestThrow();
obj.checkNum(-3);
System.out.println("Rest of the code..");
}
}
public class TestThrows
{
public static int divideNum(int m, int n) throws ArithmeticException
{
int div = m / n;
return div;
}

public static void main(String[] args)


{
TestThrows obj = new TestThrows();
try
{
System.out.println(obj.divideNum(45, 0));
}
catch (ArithmeticException e)
{
System.out.println("\nNumber cannot be divided by 0");
}
System.out.println("Rest of the code..");
}
public class TestThrowAndThrows
{
// defining a user-defined method
// which throws ArithmeticException
static void method() throws ArithmeticException
{
System.out.println("Inside the method()");
throw new ArithmeticException("throwing ArithmeticException");
}

public static void main(String args[])


{
try
{
method();
}
catch(ArithmeticException e)
{
System.out.println("caught in main() method");
}
}
}
Exception Handling with Method
Overriding
• If the superclass method does not declare an exception
•subclass overridden method cannot declare the
checked exception but it can declare unchecked
exception.
• If the superclass method declares an exception
•subclass overridden method can declare same,
subclass exception or no exception but cannot declare
parent exception.
import java.io.*; the superclass method does not declare an
class Parent{ exception, subclass overridden method
// defining the method cannot declare the checked exception.
void msg() {
System.out.println("parent method");
}
}

public class TestExceptionChild extends Parent


{
// overriding the method in child class
// gives compile time error
void msg() throws IOException {
System.out.println("TestExceptionChild");
}

public static void main(String args[]) {


Parent p = new TestExceptionChild();
p.msg();
}
}
superclass method does not declare an
exception, subclass overridden method
import java.io.*; cannot declare the checked exception but
class Parent{ can declare unchecked exception.
void msg() {
System.out.println("parent method");
}
}

class TestExceptionChild1 extends Parent{


void msg()throws ArithmeticException {
System.out.println("child method");
}

public static void main(String args[]) {


Parent p = new TestExceptionChild1();
p.msg();
}
}
import java.io.*; Example in case subclass overridden
class Parent{ method declares parent exception
void msg()throws ArithmeticException {
System.out.println("parent method");
}
}

public class TestExceptionChild2 extends


Parent{
void msg()throws Exception {
System.out.println("child method");
}

public static void main(String args[]) {


Parent p = new TestExceptionChild2();

try {
p.msg();
}
catch (Exception e){}

}
}
import java.io.*; Example in case subclass overridden
class Parent{ method declares same exception
void msg() throws Exception {
System.out.println("parent method");
}
}

public class TestExceptionChild3 extends


Parent {
void msg()throws Exception {
System.out.println("child method");
}

public static void main(String args[]){


Parent p = new TestExceptionChild3();

try {
p.msg();
}
catch(Exception e) {}
}
}
import java.io.*; Example in case subclass overridden
class Parent{ method declares subclass exception
void msg()throws Exception {
System.out.println("parent method");
}
}

class TestExceptionChild4 extends Parent{


void msg()throws ArithmeticException {
System.out.println("child method");
}

public static void main(String args[]){


Parent p = new TestExceptionChild4();

try {
p.msg();
}
catch(Exception e) {}
}
}
import java.io.*; Example in case subclass overridden
class Parent { method declares no exception
void msg()throws Exception{
System.out.println("parent method");
}
}

class TestExceptionChild5 extends Parent{


void msg() {
System.out.println("child method");
}

public static void main(String args[]){


Parent p = new TestExceptionChild5();

try {
p.msg();
}
catch(Exception e) {}

}
}
Custom Exception

• Create our own exceptions that are derived classes of


the Exception class. Creating our own Exception is
known as custom exception or user-defined exception.
• A string can be passed to the constructor of superclass
i.e. Exception class.
• This string can be obtained using getMessage() method
on the object we have created.
• Reasons to use custom exceptions:
• To catch and provide specific treatment to a subset
of existing Java exceptions.
• Business logic exceptions
Custom Exception: Example
public class WrongFileNameException extends Exception
{
public WrongFileNameException(String errorMessage)
{
super(errorMessage);
}
}
class InvalidAgeException extends Exception public static void main(String args[])
{ {
public InvalidAgeException (String str) try
{ {
super(str); validate(13);
} }
} catch (InvalidAgeException ex)
{ System.out.println("Caught the
public class TestCustomException1 exception");
{ System.out.println("Exception occured: "
static void validate (int age) throws + ex);
InvalidAgeException }
{ System.out.println("rest of the code...");
if(age < 18) }
{ }
throw new InvalidAgeException("age is not valid
to vote");
}
else
{
System.out.println("welcome to vote");
}}
class MyCustomException extends Exception
{

public class TestCustomException2


{
public static void main(String args[])
{
try
{
// throw an object of user defined exception
throw new MyCustomException();
}
catch (MyCustomException ex)
{
System.out.println("Caught the exception");
System.out.println(ex.getMessage());
}

System.out.println("rest of the code...");


}
}
Multithreading
• Multithreading is a process of executing multiple threads
simultaneously.
• A thread is a lightweight sub-process, the smallest unit of
processing.
• Threads use a shared memory area. They don't allocate
separate memory area so saves memory, and context-
switching between the threads takes less time than
process.
• Java Multithreading is mostly used in games, animation,
etc.
Process Model
▪ A process is a sequential program in execution.
▪ A process is a unit of computation.
▪ Process components:
▪ The program (code) to be executed.
▪ The data on which the program will execute.
▪ Resources required by the program.
▪ The status of the process execution.
▪ A process runs in an abstract machine environment (could be OS) that
manages the sharing and isolation of resources among the community of
processes.
Code Data
Process Status
Resource

Abstract Machine Environment


Program and Process
Program and process – distinction?
▪ A program is a static entity made up of program statements. The
latter define the run-time behavior.

▪ A process is a dynamic entity that executes a program on a


particular set of data.

▪ Two or more processes could execute the same program, each


using their own data and resources.
Thread
▪ A thread is an alternative form (to the process) of schedulable unit of
computation.
▪ In the thread model:
▪ Each thread is associated with a process.
▪ A thread is an entity that executes by relying on the code and resources,
holding by the associated process.
▪ Several threads could be associated with a single process. Those threads
share the code and resources of the process.
▪ A thread allocates part of the process’s resources for its needs.
▪ A thread has its own data and status.

Resource

Process Thread

Data Code Data


Process Status Thread Status
Thread
• A thread is a lightweight subprocess, the
smallest unit of processing.

• It is a separate path of execution.

• Threads are independent. If there


occurs exception in one thread, it
doesn't affect other threads.

• It uses a shared memory area.

As shown in the above figure, a thread is


executed inside the process. There is context-
switching between the threads. There can be
multiple processes inside the OS, and one
process can have multiple threads.
Single and Multithreaded Processes
Concurrency and Parallelism

▪ Concurrent multithreading systems give the appearance of


several tasks executing at once, but these tasks are actually
split up into chunks that share the processor with chunks from
other tasks.
▪ In parallel systems, two tasks are actually performed
simultaneously. Parallelism requires a multi-CPU system.
Java Thread class

• Java provides Thread class to achieve thread programming.

• Thread class provides constructors and methods to create


and perform operations on a thread.

• Thread class extends Object class and implements Runnable


interface.

• Java Thread methods: void start(), void run(), static void


sleep() etc.
Life cycle of a Thread
Life cycle of a Thread

A thread always exists in any one of the following states. These


states are:

• New
• Active
• Blocked / Waiting
• Timed Waiting
• Terminated

1. New: Whenever a new thread is created, it is always in the


new state. For a thread in the new state, the code has not
been run yet and thus has not begun its execution.
Life cycle of a Thread

2. Active: When a thread invokes the start() method, it moves


from the new state to the active state. The active state
contains two states within it: one is runnable, and the other is
running.

• Runnable: A thread, that is ready to run is then moved to


the runnable state. In the runnable state, the thread may
be ready to run at any given instant of time. It is the duty of
the thread scheduler to provide the thread time to run, i.e.,
moving the thread the running state.

• All those threads that are willing to run, waiting for their
turn to run, lie in the runnable state.

• In the runnable state, there is a queue where the threads


lie.
Life cycle of a Thread

• Running: When the thread gets the CPU, it moves from


the runnable to the running state.

3. Blocked or Waiting: Whenever a thread is inactive for a


span of time (not permanently) then, either the thread is in
the blocked state or is in the waiting state.

• For example, a thread (let's say its name is A) may want to print some data
from the printer. However, at the same time, the other thread (let's say its
name is B) is using the printer to print some data. Therefore, thread A has to
wait for thread B to use the printer. Thus, thread A is in the blocked state. A
thread in the blocked state is unable to perform any execution and thus
never consume any cycle of the Central Processing Unit (CPU). Hence, we
can say that thread A remains idle until the thread scheduler reactivates
thread A, which is in the waiting or blocked state.
Life cycle of a Thread

When the main thread invokes the join() method then, it is


said that the main thread is in the waiting state. The main
thread then waits for the child threads to complete their
tasks. When the child threads complete their job, a
notification is sent to the main thread, which again moves
the thread from waiting to the active state.

If there are a lot of threads in the waiting or blocked state,


then it is the duty of the thread scheduler to determine which
thread to choose and which one to reject, and the chosen
thread is then given the opportunity to run.
Life cycle of a Thread

4. Timed Waiting: Thread lies in the waiting state for a specific


span of time, and not forever.

• A real example of timed waiting is when we invoke the


sleep() method on a specific thread.

• The sleep() method puts the thread in the timed wait


state.

• After the time runs out, the thread wakes up and start its
execution from when it has left earlier.
Life cycle of a Thread

5. Terminated: A thread reaches the termination state because


of the following reasons:

• When a thread has finished its job, then it exists or


terminates normally.
• Abnormal termination: It occurs when some unusual
events such as an unhandled exception.
How to create threads
There are two ways to create a thread:
• By extending Thread class
• By implementing Runnable interface.

Thread class:
• Thread class provide constructors and methods to create and perform
operations on a thread.

• Thread class extends Object class and implements Runnable


interface.

Commonly used Constructors of Thread class:


• Thread()
• Thread(String name)
• Thread(Runnable r)
• Thread(Runnable r, String name)
How to create threads
Commonly used methods of Thread class:
• public void run(): is used to perform action for a thread.
• public void start(): starts the execution of the thread. JVM calls the
run() method on the thread.
• public void sleep(long miliseconds): Causes the currently executing
thread to sleep (temporarily cease execution) for the specified number of
milliseconds.
• public void join(): waits for a thread to die.
• public void join(long miliseconds): waits for a thread to die for the
specified miliseconds.
• public int getPriority(): returns the priority of the thread.
• public int setPriority(int priority): changes the priority of the thread.
• public String getName(): returns the name of the thread.
• public void setName(String name): changes the name of the thread.
• public Thread currentThread(): returns the reference of currently
executing thread.
• public int getId(): returns the id of the thread.
• public Thread.State getState(): returns the state of the thread.
• public boolean isAlive(): tests if the thread is alive.
How to create threads
Commonly used methods of Thread class:
• public void yield(): causes the currently executing thread object to
temporarily pause and allow other threads to execute.
• public void suspend(): is used to suspend the thread(depricated).
• public void resume(): is used to resume the suspended
thread(depricated).
• public void stop(): is used to stop the thread(depricated).
• public boolean isDaemon(): tests if the thread is a daemon thread.
• public void setDaemon(boolean b): marks the thread as daemon or
user thread.
• public void interrupt(): interrupts the thread.
• public boolean isInterrupted(): tests if the thread has been
interrupted.
• public static boolean interrupted(): tests if the current thread has
been interrupted.
How to create threads: using Runnable
Runnable interface:
The Runnable interface should be implemented by any class whose
instances are intended to be executed by a thread. Runnable interface
have only one method named run().

public void run(): is used to perform action for a thread.

Starting a thread:
The start() method of Thread class is used to start a newly created thread.
It performs the following tasks:
•A new thread starts (with new callstack).
•The thread moves from New state to the Runnable state.
•When the thread gets a chance to execute, its target run() method will
run.
Thread Example by extending Thread class

class Test extends Thread


{
public void run()
{
System.out.println("thread is running...");
}
public static void main(String args[])
{
Test t1=new Test();
t1.start();
}
} Output:

thread is running...
Thread Example by implementing Runnable interface

class Test implements Runnable


{
public void run()
{
System.out.println("thread is running...");
}

public static void main(String args[])


{
Test m1=new Test();
Thread t1 =new Thread(m1); // Using the constructor Thread (Runnable r)
t1.start();
}
}
Output:

thread is running...
Using the Thread Class: Thread(String Name)
We can directly use the Thread class to
public class Main spawn new threads
{
// Main method
public static void main(String argvs[])
{
// creating an object of the Thread class using the constructor Thread(String
name)
Thread t= new Thread("My first thread");

// the start() method moves the thread to the active state


t.start();
// getting the thread name by invoking the getName() method
String str = t.getName();
System.out.println(str);
}
Output:
}
My first thread
public class Main implements Runnable
Using the Thread Class:
{
Thread(Runnable r, String name)
public void run()
{
System.out.println("Now the thread is running ...");
}

// main method
public static void main(String argvs[])
{
// creating an object of the class Main
Runnable r1 = new Main();

// creating an object of the class Thread using Thread(Runnable r, String name)


Thread th1 = new Thread(r1, "My new thread");

// the start() method moves the thread to the active state


th1.start();
// getting the thread name by invoking the getName() method
String str = th1.getName();
System.out.println(str);
}
}
Thread Scheduler

A component of Java that decides which thread to run or execute and which
thread to wait is called a thread scheduler in Java.

A thread is only chosen by a thread scheduler if it is in the runnable state.

There are some criteria that decide which thread will execute first. There are two
factors for scheduling a thread i.e. Priority and Time of arrival.

Priority: Priority of each thread lies between 1 to 10. If a thread has a higher
priority, it means that thread has got a better chance of getting picked up by the
thread scheduler.

Time of Arrival: Suppose two threads of the same priority enter the runnable
state, then priority cannot be the factor to pick a thread from these two threads. In
such a case, arrival time of thread is considered. A thread that arrived first gets
the preference over the other threads.
Thread Scheduler Algorithms

First Come First Serve Scheduling:


In this scheduling algorithm, the scheduler picks the threads that arrive first in the
runnable queue.

Threads Time of Arrival

t1 0 We can see that Thread t1 has arrived first, then


t2 1 Thread t2, then t3, and at last t4, and the order in
which the threads will be processed is according to
t3 2
the time of arrival of threads.
t4 3
Thread Scheduler Algorithms
Time-slicing scheduling:
First Come First Serve algorithm is non-preemptive, which is bad as it may lead to
infinite blocking (also known as starvation).

To avoid that, some time-slices are provided to the threads so that after some time, the
running thread has to give up the CPU. Thus, the other waiting threads also get time to
run their job.

Each thread is given a time slice of 2 seconds.


Thus, after 2 seconds, the first thread leaves the
CPU, and the CPU is then captured by Thread2.
The same process repeats for the other threads
too.
Thread Scheduler Algorithms

Preemptive-Priority Scheduling:

Suppose there are multiple threads


available in the runnable state. The thread
scheduler picks that thread that has the
highest priority. Since the algorithm is also
preemptive, therefore, time slices are also
provided to the threads to avoid starvation.
Thus, after some time, even if the highest
priority thread has not completed its job, it
has to release the CPU because of
preemption.
Working of the Java Thread Scheduler
Suppose,
. there are five threads that have
different arrival times and different priorities.

The thread scheduler selects the thread that has


the highest priority, and the thread begins the
execution of the job. If a thread is already in
runnable state and another thread (that has
higher priority) reaches in the runnable state,
then the current thread is pre-empted from the
processor, and the arrived thread with higher
priority gets the CPU time.

When two threads (Thread 2 and Thread 3)


having the same priorities and arrival time, the
scheduling will be decided on the basis of FCFS
algorithm. Thus, the thread that arrives first gets
the opportunity to execute first.
Thread.sleep() with examples
• Java Thread class provides the two variant of the sleep() method.
.
• First one accepts only an arguments, whereas the other variant accepts two
arguments.
• The method sleep() is being used to halt the working of a thread for a given
amount of time.
• The time up to which the thread remains in the sleeping state is known as the
sleeping time of the thread.
• After the sleeping time is over, the thread starts its execution from where it has
left.

The sleep() Method Syntax:


• public static void sleep(long mls) throws InterruptedException
• public static void sleep(long mls, int n) throws InterruptedException

The Thread.sleep() method can be used with any thread. It means any other thread
or the main thread can invoke the sleep() method.

mls: The time in milliseconds is represented by the parameter mls. The duration for
which the thread will sleep is given by the method sleep().
n: It shows the additional time up to which the programmer or developer wants the
thread to be in the sleeping state. The range of n is from 0 to 999999.
Thread.sleep() with examples

• Whenever the Thread.sleep() methods


. execute, it always halts the execution of
the current thread.

• Whenever another thread does interruption while the current thread is already in
the sleep mode, then the InterruptedException is thrown.

• If the system that is executing the threads is busy, then the actual sleeping time
of the thread is generally more as compared to the time passed in arguments.

• However, if the system executing the sleep() method has less load, then the
actual sleeping time of the thread is almost equal to the time passed in the
argument.
class Test extends Thread
{
public void run()
{ .
for(int i=1;i<5;i++)
{
// the thread will sleep for the 500 milli seconds
try
{
Thread.sleep(500);
}
catch(InterruptedException e)
{
System.out.println(e);} Output:
System.out.println(i);
} 1
} 1
public static void main(String args[]) 2
{ 2
Test t1=new Test(); 3
Test t2=new Test(); 3
t1.start(); 4
t2.start(); 4
}
}
public class Main
{
// main method
public static void main(String argvs[]) .
{
try
{
for (int j = 0; j < 5; j++)
{
// The main thread sleeps for the 1000 milliseconds, which is 1 sec
// whenever the loop runs
Thread.sleep(1000);
// displaying the value of the variable
System.out.println(j);
}
} O/P:
catch (Exception expn)
{ 0
// catching the exception 1
System.out.println(expn); 2
} 3
} 4
}
public class Main
{
public static void main(String argvs[]) .
{
try
{
for (int j = 0; j < 5; j++)
{
// it throws the exception IllegalArgumentException
// as the time is -ive which is -100
Thread.sleep(-100);
System.out.println(j);
}
}
catch (Exception expn)
{
System.out.println(expn);
}
}
}
O/P:
java.lang.IllegalArgumentException: timeout value is negative
class TestCallRun1 extends Thread{
public void run() .
{
System.out.println("running...");
}
public static void main(String args[])
{
TestCallRun1 t1=new TestCallRun1();
t1.run();//fine, but does not start a separate call
stack
}
} Each thread starts in a separate call stack.
Output:
Invoking the run() method from the main
thread, the run() method goes onto the
running..
current call stack rather than at the
beginning of a new call stack.
class ThreadTest extends Thread Java code to see that all threads are
{
public void run()
pushed on same stack if we use run()
{ instead of start().
try
{
// Displaying the thread that is running
System.out.println ("Thread " +
Thread.currentThread().getId() +
" is running");

}
catch (Exception e)
{
System.out.println ("Exception is caught");
}
}
}
public class Main Output:
{ Thread 1 is running
public static void main(String[] args)
{ Thread 1 is running
int n = 8; Thread 1 is running
for (int i=0; i<8; i++) Thread 1 is running
{
ThreadTest object = new ThreadTest();
Thread 1 is running
Thread 1 is running
object.run(); Thread 1 is running
} Thread 1 is running
}
}
class ThreadTest extends Thread Java code to see that all threads are
{
public void run()
pushed on same stack if we use run()
{ instead of start().
try
{
// Displaying the thread that is running
System.out.println ("Thread " +
Thread.currentThread().getId() +
" is running");

}
catch (Exception e)
{
System.out.println ("Exception is caught");
}
}
}
public class Main Output:
{ Thread 12 is running
public static void main(String[] args)
{ Thread 18 is running
int n = 8; Thread 11 is running
for (int i=0; i<8; i++) Thread 13 is running
{
ThreadTest object = new ThreadTest();
Thread 15 is running
Thread 17 is running
object.start(); Thread 16 is running
} Thread 14 is running
}
}
Threads implement their own stack - demonstration using program and diagram
class TestCallRun2 extends Thread
{
public void run() here is no context-switching because here
{ t1 and t2 will be treated as normal object
for(int i=1;i<5;i++) not thread object.
{
try
{
Thread.sleep(500);
}
catch(InterruptedException e)
{
System.out.println(e);
} Output:
System.out.println(i); 1
} 2
} 3
public static void main(String args[]) 4
{ 1
TestCallRun2 t1=new TestCallRun2(); 2
TestCallRun2 t2=new TestCallRun2(); 3
t1.run(); 4
t2.run();
} }
class TestCallRun2 extends Thread
{
public void run() here is context-switching because here t1
{ and t2 will be treated as thread object.
for(int i=1;i<5;i++)
{
try
{
Thread.sleep(500);
}
catch(InterruptedException e)
{
System.out.println(e);
} Output:
System.out.println(i); 1
} 1
} 2
public static void main(String args[]) 2
{ 3
TestCallRun2 t1=new TestCallRun2(); 3
TestCallRun2 t2=new TestCallRun2(); 4
t1.start(); 4
t2.start();
} }
join() method

• join(): The join() method in Java is provided by the java.lang.Thread class


that permits one thread to wait until the other thread to finish its execution.
Suppose th be the object the class Thread whose thread is doing its
execution currently, then the th.join(); statement ensures that th is finished
before the program does the execution of the next statement.

• When the join() method is invoked, the current thread stops its execution
and the thread goes into the wait state. The current thread remains in the
wait state until the thread on which the join() method is invoked has
achieved its dead state. If interruption of the thread occurs, then it throws
the InterruptedException.

Syntax: public final void join() throws InterruptedException

However, similar to the sleep() method in Java, the join() method is also
dependent on the operating system for the timing, so we should not assume
that the join() method waits equal to the time we mention in the parameters.
join() method

join(long mls): When the join() method is invoked, the current thread stops its
execution and the thread goes into the wait state. The current thread remains in the
wait state until the thread on which the join() method is invoked called is dead or the
wait for the specified time frame(in milliseconds) is over.

Syntax:
public final synchronized void join(long mls) throws InterruptedException

join(long mls, int nanos): When the join() method is invoked, the current thread stops
its execution and go into the wait state. The current thread remains in the wait state
until the thread on which the join() method is invoked called is dead or the wait for
the specified time frame(in milliseconds + nanos) is over.

Syntax:

public final synchronized void join(long mls, int nanos) throws InterruptedException
import java.io.*;
import java.util.*;

public class Main extends Thread{


public void run(){
for(int i=1;i<=4;i++){
try{
Thread.sleep(500);
}catch(Exception e){System.out.println(e);}
System.out.println(i);
}
} O/P:
public static void main(String args[]){ 1
Main th1=new Main ();
Main th2=new Main ();
2
Main th3=new Main (); 3
th1.start(); 4
try{ 1
th1.join(); 1
} 2
catch(Exception e){ 2
System.out.println(e);
3
}
th2.start();
3
th3.start(); 4
} 4
}
import java.io.*;
import java.util.*;

public class Main extends Thread{


public void run(){
for(int i=1;i<=4;i++){
try{
Thread.sleep(500);
}catch(Exception e){System.out.println(e);}
System.out.println(i);
}
}
public static void main(String args[]){
Main th1=new Main ();
Main th2=new Main ();
Main th3=new Main ();
th1.start();
//try{
//th1.join();
//}
//catch(Exception e){
// System.out.println(e);
// }

th2.start();
th3.start();
}
O/P:
1
1
1
2
2
2
3
3
3
4
4
4
import java.io.*;
import java.util.*;

public class Main extends Thread{


public void run(){
for(int i=1;i<=4;i++){
try{
//Thread.sleep(500);
}catch(Exception e){System.out.println(e);}
System.out.println(i);
}
}
public static void main(String args[]){
Main th1=new Main ();
Main th2=new Main ();
Main th3=new Main ();
th1.start();
//try{
//th1.join();
//}
//catch(Exception e){
// System.out.println(e);
// }

th2.start();
th3.start();
}
O/P:
1
2
3
4
1
2
3
4
1
2
3
4
import java.io.*; th1.start();
// starting the second thread after when
class ThreadJoin extends Thread // the first thread th1 has ended or died.
{ try
public void run() {
{ System.out.println("The current thread name is: "+
for (int j = 0; j < 2; j++) Thread.currentThread().getName());
{ // invoking the join() method
try th1.join();
{ }
Thread.sleep(300); catch(Exception e)
System.out.println("The current thread name is: " + {
Thread.currentThread().getName()); System.out.println("The exception has been caught " +
} e);
catch(Exception e) }
{ th2.start();
System.out.println("The exception has been caught: " + // starting the th3 thread after when the thread th2 has
e); ended or died.
} try
System.out.println( j ); {
} System.out.println("The current thread name is: " +
} Thread.currentThread().getName());
} th2.join();
public class ThreadJoinExample }
{ catch(Exception e)
public static void main (String argvs[]) {
{ System.out.println("The exception has been caught " +
ThreadJoin th1 = new ThreadJoin(); e);
ThreadJoin th2 = new ThreadJoin(); }
ThreadJoin th3 = new ThreadJoin(); th3.start();
}}
O/P

The current thread name is: main


The current thread name is: Thread - 0
0
The current thread name is: Thread - 0
1
The current thread name is: main
The current thread name is: Thread - 1
0
The current thread name is: Thread - 1
1
The current thread name is: Thread - 2
0
The current thread name is: Thread - 2
1

The above program shows that the second thread th2 begins after the first thread
th1 has ended, and the thread th3 starts its work after the second thread th2 has
ended or died.
class TestJoinMethod1 extends Thread
{ when t1 completes its task then t2 and t3
public void run() starts executing.
{
for(int i=1;i<=5;i++)
{
try{
Thread.sleep(500); O/P:
}catch(Exception e){System.out.println(e);} 1
System.out.println(i); 2
} 3
} 4
public static void main(String args[]){ 5
TestJoinMethod1 t1=new TestJoinMethod1(); 1
TestJoinMethod1 t2=new TestJoinMethod1(); 1
TestJoinMethod1 t3=new TestJoinMethod1(); 2
t1.start(); 2
try{ 3
t1.join(); 3
}catch(Exception e){System.out.println(e);} 4
4
t2.start(); 5
t3.start(); 5
}}
class TestJoinMethod2 extends Thread{ when t1 completes its task for 1500
public void run(){ milliseconds(3 times), then t2 and t3 start
for(int i=1;i<=5;i++){ executing.
try{
Thread.sleep(500);
}catch(Exception e){System.out.println(e);}
System.out.println(i); O/P: O/P:
} 1 1
} 2 2
public static void main(String args[]){ 3 3
TestJoinMethod2 t1=new TestJoinMethod2(); 1 1
TestJoinMethod2 t2=new TestJoinMethod2(); 4 1
TestJoinMethod2 t3=new TestJoinMethod2(); 1 4
t1.start(); 2 2
try{ 5 2
t1.join(1500); 2 5
}catch(Exception e){System.out.println(e);} 3 3
3 3
t2.start(); 4 4
t3.start(); 4 4
} } 5 5
5 5
Naming Thread

The Thread class provides methods to change and get the name of a thread. By
default, each thread has a name, i.e. thread-0, thread-1 and so on. By we can
change the name of the thread by using the setName() method. The syntax of
setName() and getName() methods are given below:

public String getName(): is used to return the name of a thread.

public void setName(String name): is used to change the name of a thread.


Example of naming a thread : Using setName() Method

class Test extends Thread


{
public void run()
{
System.out.println("running...");
}
public static void main(String args[])
{
Test t1=new Test();
Test t2=new Test();
System.out.println("Name of t1:"+t1.getName());
System.out.println("Name of t2:"+t2.getName());
t1.start();
O/P:
t2.start();
Name of t1:Thread-0
t1.setName("Learning threads");
Name of t2:Thread-1
System.out.println("After changing name of
After changing name of t1:Learning
t1:"+t1.getName());
threads
}
running...
}
running...
Example of naming a thread : Without Using setName()
Method
import java.io.*;

class ThreadName extends Thread


{
ThreadName(String threadName)
{
super(threadName);
}
public void run()
{
System.out.println(" The thread is executing....");
}
}
public class ThreadNamingExample
{
public static void main (String argvs[])
{
ThreadName th1 = new ThreadName(“Java Thread1"); Output:
ThreadName th2 = new ThreadName(“Java Thread 2");
Thread - 1: JavaThread1
System.out.println("Thread - 1: " + th1.getName());
System.out.println("Thread - 2: " + th2.getName());
Thread - 2: JavaThread2
The thread is executing....
th1.start(); The thread is executing....
th2.start();
} }
Current Thread
The currentThread() method returns a reference of the currently executing
thread.
public static Thread currentThread()

class Test extends Thread{


public void run()
{
System.out.println(Thread.currentThread().getName());
}
public static void main(String args[])
{
Test t1=new Test();
Test t2=new Test();

t1.start(); O/P:
t2.start();
} Thread-0
} Thread-1
Thread Priority

Setter & Getter Method of Thread Priority


public final int getPriority(): The java.lang.Thread.getPriority() method returns the
priority of the given thread.

public final void setPriority(int newPriority): The java.lang.Thread.setPriority()


method updates or assign the priority of the thread to newPriority.

The method throws IllegalArgumentException if the value newPriority goes out of


the range, which is 1 (minimum) to 10 (maximum).

Constants defined in Thread class:


public static int MIN_PRIORITY
public static int NORM_PRIORITY
public static int MAX_PRIORITY

Default priority of a thread is 5 (NORM_PRIORITY). The value of MIN_PRIORITY is


1 and the value of MAX_PRIORITY is 10.
Thread Priority
import java.lang.*;
public class ThreadPriorityExample extends Thread
{
public void run()
{
System.out.println("Inside the run() method");
}

public static void main(String argvs[])


{
ThreadPriorityExample th1 = new ThreadPriorityExample();
ThreadPriorityExample th2 = new ThreadPriorityExample();
ThreadPriorityExample th3 = new ThreadPriorityExample();
System.out.println("Priority of the thread th1 is : " + th1.getPriority());
System.out.println("Priority of the thread th2 is : " + th2.getPriority());
System.out.println("Priority of the thread th3 is : " + th3.getPriority());
th1.setPriority(6);
th2.setPriority(3);
th3.setPriority(9);
System.out.println("Priority of the thread th1 is : " + th1.getPriority());
System.out.println("Priority of the thread th2 is : " + th2.getPriority());
System.out.println("Priority of the thread th3 is : " + th3.getPriority());
System.out.println("Currently Executing Thread:"+Thread.currentThread().getName());
System.out.println("Priority of the main thread is :"+Thread.currentThread().getPriority());
Thread.currentThread().setPriority(10);
System.out.println("Priority of main thread is : " + Thread.currentThread().getPriority());
}
}

O/P:
Priority of the thread th1 is : 5
Priority of the thread th2 is : 5
Priority of the thread th3 is : 5
Priority of the thread th1 is : 6
Priority of the thread th2 is : 3
Priority of the thread th3 is : 9
Currently Executing The Thread : main
Priority of the main thread is : 5
Priority of the main thread is : 10
// th1 thread is the child of the main
thread
import java.lang.*; // therefore, the th1 thread also gets the
priority 7
public class ThreadPriorityExample1 extends
Thread
{
public void run()
{
System.out.println("Inside the run() method");
}

public static void main(String argvs[])


{
Thread.currentThread().setPriority(7);
System.out.println("Priority of the main thread
is : " + Thread.currentThread().getPriority());
ThreadPriorityExample1 th1 = new
ThreadPriorityExample1();
System.out.println("Priority of the thread th1
is : " + th1.getPriority());
}
}
import java.lang.*;

public class Main extends Thread


{
public void run()
{
System.out.println("Inside the run() method");
}

public static void main(String argvs[])


{
Main th1 = new Main();
System.out.println("Priority of the thread th1
is : " + th1.getPriority());
Thread.currentThread().setPriority(7);
System.out.println("Priority of the main thread
is : " + Thread.currentThread().getPriority());
//Main th1 = new Main();
//System.out.println("Priority of the thread th1
is : " + th1.getPriority());
Priority of the thread th1 is : 5
}
Priority of the main thread is : 7
}
Thread-0 7 main 7 Thread-1 7
class Main extends Thread{
public void run()
{

System.out.println(currentThread().getName(
));

System.out.println(currentThread().getPriority
());
}
public static void main(String args[])
{ currentThread().setPriority(7);
Main t1=new Main();
Main t2=new Main();
//currentThread().setPriority(7);
t1.start();
t2.start();
//currentThread().setPriority(8);

System.out.println(currentThread().getName(
));
System.out.println(currentThread().getPriority
());
}}
O/P:
Thread-0
7
main
7
Thread-1
7
Example of IllegalArgumentException

We know that if the value of the parameter newPriority of the method getPriority()
goes out of the range (1 to 10), then we get the IllegalArgumentException.

import java.lang.*;
public class IllegalArgumentException extends Thread
{
public static void main(String argvs[])
{

Thread.currentThread().setPriority(17);
System.out.println("Priority of the main thread is : " +
Thread.currentThread().getPriority());
}
}

O/P:
Exception in thread "main" java.lang.IllegalArgumentException
at java.base/java.lang.Thread.setPriority(Thread.java:1141)
at IllegalArgumentException.main(IllegalArgumentException.java:12)
Daemon Thread

Daemon thread in Java is a service provider thread that provides services to the
user thread. Its life depend on the mercy of user threads i.e. when all the user
threads dies, JVM terminates this thread automatically.

• It provides services to user threads for background supporting tasks. It has no


role in life than to serve user threads.
• Its life depends on user threads.
• It is a low priority thread.

The java.lang.Thread class provides two methods for java daemon thread.

1) public void setDaemon(boolean status): is used to mark the current thread as daemon
thread or user thread.

2)public boolean isDaemon(): is used to check that current is daemon.


public class TestDaemonThread1 extends Thread
{
public void run()
{
if(Thread.currentThread().isDaemon())
{
System.out.println("daemon thread work");
}
else
{
System.out.println("user thread work");
}
}
public static void main(String[] args)
{
TestDaemonThread1 t1=new TestDaemonThread1();//creating thread
TestDaemonThread1 t2=new TestDaemonThread1();
TestDaemonThread1 t3=new TestDaemonThread1();
t1.setDaemon(true);//now t1 is daemon thread Output:
t1.start();//starting threads
t2.start(); daemon thread work
t3.start(); user thread work
} user thread work
}
class TestDaemonThread2 extends Thread
{
public void run()
{
System.out.println("Name: "+Thread.currentThread().getName());
System.out.println("Daemon: "+Thread.currentThread().isDaemon());
}

public static void main(String[] args)


{
TestDaemonThread2 t1=new TestDaemonThread2();
TestDaemonThread2 t2=new TestDaemonThread2();
t1.start();
t1.setDaemon(true);//will throw exception here
t2.start();
}
} If you want to make a user thread as
Daemon, it must not be started otherwise it
Output: will throw IllegalThreadStateException.

exception in thread main:


java.lang.IllegalThreadStateException
Synchronization
• It is the capability to control the access of multiple threads to
any shared resource.
• Synchronization is better option where we want to allow only
one thread to access the shared resource.
• Synchronization is mainly used to
• To prevent thread interference.
• To prevent consistency problem.
• There are two types of synchronization
• Process Synchronization
• Thread Synchronization
• Two types : 1) Mutual Exclusive 2) inter-thread
communication.
• Mutual Exclusive: It helps keep threads from interfering with
one another while sharing data.
• Synchronized method.
• Synchronized block.
• Static synchronization.
Concept of Lock
• Synchronization is built around an internal entity known as the
lock or monitor.
• A thread that needs consistent access to an object's fields has
to acquire the object's lock before accessing them, and then
release the lock when it's done with them.
class Table class MyThread2 extends Thread
{ {
void printTable(int n) Table t;
{ MyThread2(Table t)
for(int i=1;i<=5;i++) {
{ this.t=t;
System.out.println(n*i); }
try{ public void run()
Thread.sleep(400); {
} t.printTable(100);
catch(Exception e){System.out.println(e);} }
} }
} class TestSynchronization1
} {
class MyThread1 extends Thread public static void main(String args[])
{ {
Table t; Table obj = new Table();
MyThread1(Table t) MyThread1 t1=new MyThread1(obj);
{ MyThread2 t2=new MyThread2(obj);
this.t=t; t1.start();
} t2.start();
public void run(){ }
t.printTable(5); }
}}
O/P:
5
100
10
200
15
300
20
400
25
500

Java Synchronized Method

• If you declare any method as synchronized, it is known as synchronized method.

• Synchronized method is used to lock an object for any shared resource.

• When a thread invokes a synchronized method, it automatically acquires the lock


for that object and releases it when the thread completes its task.
class Table class MyThread2 extends Thread
{ {
synchronized void printTable(int n) Table t;
{ MyThread2(Table t)
for(int i=1;i<=5;i++) {
{ this.t=t;
System.out.println(n*i); }
try{ public void run()
Thread.sleep(400); {
} t.printTable(100);
catch(Exception e) }
{System.out.println(e);} }
} }} public class TestSynchronization2
class MyThread1 extends Thread {
{ public static void main(String args[])
Table t; {
MyThread1(Table t) Table obj = new Table();//only one object
{ MyThread1 t1=new MyThread1(obj);
this.t=t; MyThread2 t2=new MyThread2(obj);
} t1.start();
public void run() t2.start();
{ }
t.printTable(5); }
}}
O/P:
5
10
15
20
25
100
200
300
400
500
class Table
{ Using the anonymous class
synchronized void printTable(int n)
{
for(int i=1;i<=5;i++)
{
System.out.println(n*i);
try
{
Thread.sleep(400);
}catch(Exception e){System.out.println(e);}
}}}
public class TestSynchronization3
Output:
{ public static void main(String args[]){
5
final Table obj = new Table();//only one object
10
Thread t1=new Thread(){
15
public void run(){
20
obj.printTable(5);
25
} };
100
Thread t2=new Thread(){
200
public void run(){
300
obj.printTable(100);
400
}
500
}; t1.start(); t2.start(); } }
Synchronized Block
• Synchronized block can be used to perform synchronization
on any specific resource of the method.
• Suppose we have 50 lines of code in our method, but we
want to synchronize only 5 lines, in such cases, we can use
synchronized block.
• If we put all the codes of the method in the synchronized
block, it will work same as the synchronized method.
• Java synchronized block is more efficient than Java
synchronized method.

Syntax:
synchronized (object reference expression)
{
//code block
}
class Table
class MyThread2 extends Thread
{
{
void printTable(int n)
Table t;
{
MyThread2(Table t)
synchronized(this)
{
{
this.t=t;
for(int i=1;i<=5;i++)
}
{
public void run()
System.out.println(n*i);
{
try{
t.printTable(100);
Thread.sleep(400);
}
}catch(Exception e){System.out.println(e);}
}
}}
public class TestSynchronizedBlock1
}//end of the method
{
}
public static void main(String args[])
class MyThread1 extends Thread
{
{
Table obj = new Table();//only one object
Table t;
MyThread1 t1=new MyThread1(obj);
MyThread1(Table t){
MyThread2 t2=new MyThread2(obj);
this.t=t;
t1.start();
}
t2.start();
public void run(){
}
t.printTable(5);
}
}}
O/P:
5
10
15
20
25
100
200
300
400
500
Static Synchronization
If you make any static method as synchronized, the lock will be on the class not on
object.

Problem without static synchronization


• Suppose there are two objects of a
shared class (e.g. Table) named object1
and object2.
• In case of synchronized method and
synchronized block there cannot be
interference between t1 and t2 or t3 and
t4 because t1 and t2 both refers to a
common object that have a single lock.
• But there can be interference between
t1 and t3 or t2 and t4 because t1
acquires another lock and t3 acquires
another lock.
• We don't want interference between t1
and t3 or t2 and t4. Static
synchronization solves this problem.
class Table class MyThread4 extends Thread{
{ public void run(){
synchronized static void printTable(int n){ Table.printTable(1000);
for(int i=1;i<=10;i++){ }
System.out.println(n*i); }
try{ public class TestSynchronization4{
Thread.sleep(400); public static void main(String t[]){
}catch(Exception e){} MyThread1 t1=new MyThread1();
} MyThread2 t2=new MyThread2();
} MyThread3 t3=new MyThread3();
} MyThread4 t4=new MyThread4();
class MyThread1 extends Thread{ t1.start();
public void run(){ t2.start();
Table.printTable(1); t3.start();
} t4.start();
} }
class MyThread2 extends Thread{ }
public void run(){
Table.printTable(10);
}
}
class MyThread3 extends Thread{
public void run(){
Table.printTable(100);
Output:

1
2
3
4
5
6
7
8
9
10
10
20
30
40
50
60
70
80
90
100
100
200
300
400
500
600
700
800
900
1000
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000
class Table Thread t3=new Thread()
{ {
synchronized static void printTable(int n) public void run()
{ {
for(int i=1;i<=10;i++){ Table.printTable(100);
System.out.println(n*i); }
try{ };
Thread.sleep(400); Thread t4=new Thread(){
}catch(Exception e){} public void run(){
}}} Table.printTable(1000);
public class TestSynchronization5 }
{ };
public static void main(String[] args) t1.start();
{ t2.start();
Thread t1=new Thread(){ t3.start();
public void run(){ t4.start();
Table.printTable(1); }
} }
};
Thread t2=new Thread(){
public void run(){
Table.printTable(10);
}
};
Deadlock
Deadlock can occur in a situation when a thread is waiting for an object lock, that is
acquired by another thread and second thread is waiting for an object lock that is
acquired by first thread. Since, both threads are waiting for each other to release
the lock, the condition is called deadlock.
public class TestDeadlockExample1
// t2 tries to lock resource2 then resource1
{
Thread t2 = new Thread() {
public static void main(String[] args)
public void run() {
{
synchronized (resource2) {
final String resource1 = "raman";
System.out.println("Thread 2: locked
final String resource2 = “chaman";
resource 2");
// t1 tries to lock resource1 then resource2
Thread t1 = new Thread()
try { Thread.sleep(100);} catch
{
(Exception e) {}
public void run() {
synchronized (resource1) {
synchronized (resource1) {
System.out.println("Thread 1: locked
System.out.println("Thread 2:
resource 1");
locked resource 1");
}
try { Thread.sleep(100);}
}
catch (Exception e) {}
}
};
synchronized (resource2) {
System.out.println("Thread 1: locked
resource 2");
t1.start();
}
t2.start();
}
}
}
}
};
Output:

Thread 1: locked resource 1


Thread 2: locked resource 2
public class TestThread {
public static Object Lock1 = new Object();
public static Object Lock2 = new Object();

public static void main(String args[])


{
ThreadDemo1 T1 = new ThreadDemo1();
ThreadDemo2 T2 = new ThreadDemo2();
T1.start();
T2.start();
}
private static class ThreadDemo1 extends Thread
{
public void run() {
synchronized (Lock1)
{
System.out.println("Thread 1: Holding lock 1...");
try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");

synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
} }}}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 2...");

try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 1...");

synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
} Output
} Thread 1: Holding lock 1...
} Thread 2: Holding lock 2...
Thread 1: Waiting for lock 2...
Thread 2: Waiting for lock 1...

The above program will hang forever because neither of the threads in position to
proceed and waiting for each other to release the lock, so you can come out of the
program by pressing CTRL+C.
public class TestThread {
public static Object Lock1 = new Object();
public static Object Lock2 = new Object(); Solution
public static void main(String args[]) {
ThreadDemo1 T1 = new ThreadDemo1();
ThreadDemo2 T2 = new ThreadDemo2();
T1.start();
T2.start();
}

private static class ThreadDemo1 extends Thread {


public void run() {
synchronized (Lock1) {
System.out.println("Thread 1: Holding lock 1...");

try {
Thread.sleep(10);
} catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");

synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
} }}}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1...");

try {
Thread.sleep(10);
} catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 2...");

synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
} Output So just changing the order of the locks
Thread 1: Holding lock 1... prevent the program in going into a
Thread 1: Waiting for lock 2... deadlock situation and completes with the
Thread 1: Holding lock 1 & 2... displayed result
Thread 2: Holding lock 1...
Thread 2: Waiting for lock 2...
Thread 2: Holding lock 1 & 2...
Deadlocks cannot be completely resolved. But we can avoid
them by following basic rules mentioned below:

• Avoid Nested Locks: We must avoid giving locks to multiple


threads, this is the main reason for a deadlock condition. It
normally happens when you give locks to multiple threads.
• Avoid Unnecessary Locks: The locks should be given to the
important threads. Giving locks to the unnecessary threads
that cause the deadlock condition.
• Using Thread Join: A deadlock usually happens when one
thread is waiting for the other to finish. In this case, we can
use join with a maximum time that a thread will take.
Inter-thread communication
Inter-thread communication or Co-operation is all about allowing synchronized
threads to communicate with each other.

Cooperation (Inter-thread communication) is a mechanism in which a thread is


paused running in its critical section and another thread is allowed to enter (or lock)
in the same critical section to be executed.

It is implemented by following methods of Object class:

•wait(): The wait() method causes current thread to release the lock and wait until
either another thread invokes the notify() method or the notifyAll() method for this
object, or a specified amount of time has elapsed.
•notify(): The notify() method wakes up a single thread that is waiting on this
object's monitor. If any threads are waiting on this object, one of them is chosen
to be awakened. The choice is arbitrary and occurs at the discretion of the
implementation.
•notifyAll(): Wakes up all threads that are waiting on this object's monitor.

Syntax: Syntax:
public final void notifyAll() public final void notify()
Process of inter-thread communication

1. Threads enter to acquire lock.


2. Lock is acquired by on thread.
3. Now thread goes to waiting state if you
call wait() method on the object.
Otherwise it releases the lock and exits.
4. If you call notify() or notifyAll() method,
thread moves to the notified state
(runnable state).
5. Now thread is available to acquire lock.
6. After completion of the task, thread
releases the lock and exits the monitor
state of the object.
wait() sleep()

The wait() method releases the The sleep() method doesn't


lock. release the lock.

It is a method of Object class It is a method of Thread class

It is the non-static method It is the static method

It should be notified by notify() After the specified amount of


or notifyAll() methods time, sleep is completed.
class Customer
class Test
{
{
int amount=10000;
public static void main(String args[])
synchronized void withdraw(int amount)
{
{
final Customer c=new Customer();
System.out.println("going to withdraw...");
new Thread(){
if(this.amount<amount)
public void run(){c.withdraw(15000);}
{
}.start();
System.out.println("Less balance; waiting
new Thread(){
for deposit...");
public void run(){c.deposit(10000);}
try{wait();}catch(Exception e){}
}.start();
}
}}
this.amount-=amount;
System.out.println("withdraw
completed...");
} Output:
synchronized void deposit(int amount){
System.out.println("going to deposit..."); going to withdraw...
this.amount+=amount; Less balance; waiting for deposit...
System.out.println("deposit completed... "); going to deposit...
notify(); deposit completed...
} withdraw completed
}

You might also like