0% found this document useful (0 votes)
5 views35 pages

Multithreading

Multithreading in Java allows multiple threads to execute simultaneously, utilizing shared memory for efficiency. It offers advantages such as non-blocking user experience, time-saving through concurrent operations, and independent thread execution. Java provides the Thread class and Runnable interface for thread creation, along with methods for managing thread states and synchronization.

Uploaded by

Prachi Bhatt
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)
5 views35 pages

Multithreading

Multithreading in Java allows multiple threads to execute simultaneously, utilizing shared memory for efficiency. It offers advantages such as non-blocking user experience, time-saving through concurrent operations, and independent thread execution. Java provides the Thread class and Runnable interface for thread creation, along with methods for managing thread states and synchronization.

Uploaded by

Prachi Bhatt
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/ 35

Multithreading in Java

 Multithreading in java is a process of executing multiple threads simultaneously.


 A thread is a lightweight sub-process, the smallest unit of processing. Multiprocessing
and multithreading, both are used to achieve multitasking.
 However, we use multithreading than multiprocessing because 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.

Advantages of Java Multithreading

1) It doesn't block the user because threads are independent and you can perform multiple
operations at the same time.

2) You can perform many operations together, so it saves time.

3) Threads are independent, so it doesn't affect other threads if an exception occurs in a single
thread.

Multitasking
Multitasking is a process of executing multiple tasks simultaneously. We use multitasking to
utilize the CPU. Multitasking can be achieved in two ways:

o Process-based Multitasking (Multiprocessing)


o Thread-based Multitasking (Multithreading)

1) Process-based Multitasking (Multiprocessing)

o Each process has an address in memory. In other words, each process allocates a separate
memory area.
o A process is heavyweight.
o Cost of communication between the process is high.
o Switching from one process to another requires some time for saving and loading
registers, memory maps, updating lists, etc.

2) Thread-based Multitasking (Multithreading)

o Threads share the same address space.


o A thread is lightweight.
o Cost of communication between the thread is low.
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.

How to create thread


There are two ways to create a thread:

1. By extending Thread class


2. 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)
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:
start() method of Thread class is used to start a newly created thread. It performs 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.

1) Java Thread Example by extending Thread class


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

2) Java Thread Example by implementing Runnable interface


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

public static void main(String args[]){


Multi3 m1=new Multi3();
Thread t1 =new Thread(m1);
t1.start();
}
}
Output: thread is running...

If you are not extending the Thread class,your class object would not be treated as a thread
object.So you need to explicitely create Thread class object.
We are passing the object of your class that implements Runnable so that your class run()
method may execute.

Thread Scheduler in Java


Thread scheduler in java is the part of the JVM that decides which thread should run.

 There is no guarantee that which runnable thread will be chosen to run by the thread
scheduler.
 Only one thread at a time can run in a single process.
 The thread scheduler mainly uses preemptive or time slicing scheduling to schedule the
threads.

Sleep method in java


The sleep() method of Thread class is used to sleep a thread for the specified amount of
time.

Syntax of sleep() method in java


The Thread class provides two methods for sleeping a thread:

o public static void sleep(long miliseconds)throws InterruptedException


o public static void sleep(long miliseconds, int nanos)throws InterruptedException

Example of sleep method in java


1. class TestSleepMethod1 extends Thread{
2. public void run(){
3. for(int i=1;i<5;i++){
4. try{Thread.sleep(500);}catch(InterruptedException e){System.out.println(e);}
5. System.out.println(i);
6. }
7. }
8. public static void main(String args[]){
9. TestSleepMethod1 t1=new TestSleepMethod1();
10. TestSleepMethod1 t2=new TestSleepMethod1();
11.
12. t1.start();
13. t2.start();
14. }
15. }
Output:

1
1
2
2
3
3
4
4
As you know well that at a time only one thread is executed. If you sleep a thread for the
specified time,the thread shedular picks up another thread and so on.

Can we start a thread twice


No. After starting a thread, it can never be started again. If you does so,
an IllegalThreadStateException is thrown. In such case, thread will run once but for second time,
it will throw exception.

Let's understand it by the example given below:

1. public class TestThreadTwice1 extends Thread{


2. public void run(){
3. System.out.println("running...");
4. }
5. public static void main(String args[]){
6. TestThreadTwice1 t1=new TestThreadTwice1();
7. t1.start();
8. t1.start();
9. }
10. }
OUTPUT
running
Exception in thread "main" java.lang.IllegalThreadStateException

What if we call run() method directly instead start() method?


 Each thread starts in a separate call stack.
 Invoking the run() method from main thread, the run() method goes onto the current call
stack rather than at the beginning of a new call stack.

class TestCallRun2 extends Thread{
public void run(){
for(int i=1;i<5;i++){
try{Thread.sleep(500);}catch(InterruptedException e){System.out.println(e);}
System.out.println(i);
}
}
public static void main(String args[]){
TestCallRun2 t1=new TestCallRun2();
TestCallRun2 t2=new TestCallRun2();

t1.run();
t2.run();
}
}

Output:1
2
3
4
5
1
2
3
4
5

As you can see in the above program that there is no context-switching because here t1 and t2
will be treated as normal object not thread object.
IsAlive and Join Methods(Very Important)
 Sometimes one thread needs to know when other thread is terminated or not. In java,
isAlive() and join() are two different methods that are used to check whether a thread has
finished its execution or not.

 The isAlive() method returns true if the thread upon which it is called is still running
otherwise it returns false.

final boolean isAlive()

 But, join() method is used more commonly than isAlive(). This method waits until the
thread on which it is called terminates.

final void join() throws InterruptedException


 Using join() method, we tell our thread to wait until the specified thread completes its
execution.

 There are overloaded versions of join() method, which allows us to specify time for
which you want to wait for the specified thread to terminate.
final void join(long milliseconds) throws InterruptedException

 As we have seen in the introduction to MultiThreading, the main thread must always be
the last thread to finish its execution. Therefore, we can use Thread join() method to
ensure that all the threads created by the program has been terminated before the
termination of the main thread.

Example of isAlive method

public class MyThread extends Thread


{
public void run()
{
System.out.println("r1 ");
try {
Thread.sleep(500);
}
catch(InterruptedException ie) { }
System.out.println("r2 ");
}
public static void main(String[] args)
{
MyThread t1=new MyThread();
MyThread t2=new MyThread();
t1.start();
t2.start();
System.out.println(t1.isAlive());
System.out.println(t2.isAlive());
}
}
Output :

r1
true
true
r1
r2
r2

Example of thread without join() method

public class MyThread extends Thread


{
public void run()
{
System.out.println("r1 ");
try {
Thread.sleep(500);
}
catch(InterruptedException ie){ }
System.out.println("r2 ");
}
public static void main(String[] args)
{
MyThread t1=new MyThread();
MyThread t2=new MyThread();
t1.start();
t2.start();
}
}
Output :

r1
r1
r2
r2
In this above program two thread t1 and t2 are created. t1 starts first and after printing "r1" on console
thread t1 goes to sleep for 500 ms. At the same time Thread t2 will start its process and print "r1" on
console and then go into sleep for 500 ms. Thread t1 will wake up from sleep and print "r2" on console
similarly thread t2 will wake up from sleep and print "r2" on console. So you will get output like r1 r1 r2
r2

Example of thread with join() method

public class MyThread extends Thread


{
public void run()
{
System.out.println("r1 ");
try {
Thread.sleep(500);
}catch(InterruptedException ie){ }
System.out.println("r2 ");
}
public static void main(String[] args)
{
MyThread t1=new MyThread();
MyThread t2=new MyThread();
t1.start();

try{
t1.join(); //Waiting for t1 to finish
}catch(InterruptedException ie){}

t2.start();
}
}
Output :

r1
r2
r1
r2
In this above program join() method on thread t1 ensures that t1 finishes it process before thread t2
starts.
Specifying time with join()

If in the above program, we specify time while using join() with t1, then t1 will execute for that time, and
then t2 will join it.

t1.join(1500);
Doing so, initially t1 will execute for 1.5 seconds, after which t2 will join it.

Creating Multiple Threads


So far, you have been using only two threads: the main thread and one child thread. However,
your program can spawn as many threads as it needs. For example, the following program
creates three child threads:

// Create multiple threads.

class NewThread implements Runnable {


String name; // name of thread
Thread t;
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
t.start(); // Start the thread
}
// This is the entry point for thread.
public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println(name + "Interrupted");
}
System.out.println(name + " exiting.");
}
}
class MultiThreadDemo {
public static void main(String args[]) {
new NewThread("One"); // start threads
new NewThread("Two");
new NewThread("Three");
try {
// wait for other threads to end
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");
}
}
The output from this program is shown here:
New thread: Thread[One,5,main]
New thread: Thread[Two,5,main]
New thread: Thread[Three,5,main]
One: 5
Two: 5
Three: 5
One: 4
Two: 4
Three: 4
One: 3
Three: 3
Two: 3
One: 2
Three: 2
Two: 2
One: 1
Three: 1
Two: 1
One exiting.
Two exiting.
Three exiting.
Main thread exiting.
As you can see, once started, all three child threads share the CPU. Notice the call to
sleep(10000) in main( ). This causes the main thread to sleep for ten seconds and ensures that it
will finish last.

// Using join() to wait for threads to finish.


class NewThread implements Runnable {
String name; // name of thread
Thread t;
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
t.start(); // Start the thread
}
// This is the entry point for thread.
public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println(name + " interrupted.");
}
System.out.println(name + " exiting.");
}
}
class DemoJoin {
public static void main(String args[]) {
NewThread ob1 = new NewThread("One");
NewThread ob2 = new NewThread("Two");
NewThread ob3 = new NewThread("Three");
System.out.println("Thread One is alive: "
+ ob1.t.isAlive());
System.out.println("Thread Two is alive: "
+ ob2.t.isAlive());
System.out.println("Thread Three is alive: "
+ ob3.t.isAlive());
// wait for threads to finish
try {
System.out.println("Waiting for threads to finish.");
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Thread One is alive: "
+ ob1.t.isAlive());
System.out.println("Thread Two is alive: "
+ ob2.t.isAlive());
System.out.println("Thread Three is alive: "
+ ob3.t.isAlive());
System.out.println("Main thread exiting.");
}
}
Sample output from this program is shown here. (Your output may vary based on processor
speed and task load.)

New thread: Thread[One,5,main]


New thread: Thread[Two,5,main]
New thread: Thread[Three,5,main]
Thread One is alive: true
Thread Two is alive: true
Thread Three is alive: true
Waiting for threads to finish.
One: 5
Two: 5
Three: 5
One: 4
Two: 4
Three: 4
One: 3
Two: 3
Three: 3
One: 2
Two: 2
Three: 2
One: 1
Two: 1
Three: 1
Two exiting.
Three exiting.
One exiting.
Thread One is alive: false
Thread Two is alive: false
Thread Three is alive: false
Main thread exiting.
As you can see, after the calls to join( ) return, the threads have stopped executing.

Naming Thread and Current Thread

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 setName() method. The syntax of setName() and getName() methods are given below:

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


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

Example of naming a thread


1. class TestMultiNaming1 extends Thread{
2. public void run(){
3. System.out.println("running...");
4. }
5. public static void main(String args[]){
6. TestMultiNaming1 t1=new TestMultiNaming1();
7. TestMultiNaming1 t2=new TestMultiNaming1();
8. System.out.println("Name of t1:"+t1.getName());
9. System.out.println("Name of t2:"+t2.getName());
10.
11. t1.start();
12. t2.start();
13.
14. t1.setName("Sonoo Jaiswal");
15. System.out.println("After changing name of t1:"+t1.getName());
16. }
17. }

Output:
Name of t1:Thread-0
Name of t2:Thread-1
id of t1:8
running...
After changeling name of t1:Sonoo Jaiswal
running...

Current Thread
1. class TestMultiNaming2 extends Thread{
2. public void run(){
3. System.out.println(Thread.currentThread().getName());
4. }
5. public static void main(String args[]){
6. TestMultiNaming2 t1=new TestMultiNaming2();
7. TestMultiNaming2 t2=new TestMultiNaming2();
8.
9. t1.start();
10. t2.start();
11. }
12. }
Output:Thread-0
Thread-1
Priority of a Thread (Thread Priority):
 Each thread have a priority.
 Priorities are represented by a number between 1 and 10.
 In most cases, thread scheduler schedules the threads according to their priority (known
as preemptive scheduling).
 But it is not guaranteed because it depends on JVM specification that which scheduling it
chooses.
3 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.

class TestMultiPriority1 extends Thread{


public void run(){
System.out.println("running thread name is:"+Thread.currentThread().getName());
System.out.println("running thread priority is:"+Thread.currentThread().getPriority());

}
public static void main(String args[]){
TestMultiPriority1 m1=new TestMultiPriority1();
TestMultiPriority1 m2=new TestMultiPriority1();
m1.setPriority(Thread.MIN_PRIORITY);
m2.setPriority(Thread.MAX_PRIORITY);
m1.start();
m2.start();

}
}
Output:
running thread name is:Thread-0
running thread priority is:10
running thread name is:Thread-1
running thread priority is:1
Daemon Thread in Java
 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.

 There are many java daemon threads running automatically e.g. gc, finalizer etc.

 You can see all the detail by typing the jconsole in the command prompt. The jconsole
tool provides information about the loaded classes, memory usage, running threads etc.

Points to remember for Daemon Thread in Java


 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.
Why JVM terminates the daemon thread if there is no user thread?
The sole purpose of the daemon thread is that it provides services to user thread for background
supporting task. If there is no user thread, why should JVM keep running this thread. That is why
JVM terminates the daemon thread if there is no user thread.

public class TestDaemonThread1 extends Thread{


public void run(){
if(Thread.currentThread().isDaemon()){//checking for daemon thread
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

t1.start();//starting threads
t2.start();
t3.start();
}
}

Output
daemon thread work
user thread work
user thread work
Note: If you want to make a user thread as Daemon, it must not be started otherwise it will
throw IllegalThreadStateException.

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();
}
}

Output: exception in thread main: java.lang.IllegalThreadStateException

How to perform multiple tasks by multiple threads (multitasking in multithreading)?


If you have to perform multiple tasks by multiple threads,have multiple run() methods.

class Simple1 extends Thread{


public void run(){
System.out.println("task one");
}
}

class Simple2 extends Thread{


public void run(){
System.out.println("task two");
}
}

class TestMultitasking3{
public static void main(String args[]){
Simple1 t1=new Simple1();
Simple2 t2=new Simple2();

t1.start();
t2.start();
}
}
Output:
task one
task two

Synchronization in Java
 When two or more threads need access to a shared resource, they need some way to
ensure that the resource will be used by only one thread at a time. The process by which
this is achieved is called synchronization.
 Synchronization in java is the capability to control the access of multiple threads to any
shared resource.
 Java Synchronization is better option where we want to allow only one thread to access
the shared resource.
Why use Synchronization

The synchronization is mainly used to


1. To prevent thread interference.
2. To prevent consistency problem.
Thread Synchronization

There are two types of thread synchronization mutual exclusive and inter-thread communication.
1. Mutual Exclusive
1. Synchronized method.
2. Synchronized block.
3. static synchronization.
2. Cooperation (Inter-thread communication in java)
Mutual Exclusive

Mutual Exclusive helps keep threads from interfering with one another while sharing data. This
can be done by three ways in java:
1. by synchronized method
2. by synchronized block
3. by static synchronization

Concept of Lock in Java

Synchronization is built around an internal entity known as the lock or monitor. Every object has
an lock associated with it. By convention, 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.
//example of java synchronized method
1. class Table{
2. synchronized void printTable(int n){//synchronized method
3. for(int i=1;i<=5;i++){
4. System.out.println(n*i);
5. try{
6. Thread.sleep(400);
7. }catch(Exception e){System.out.println(e);}
8. }
9.
10. }
11. }
12.
13. class MyThread1 extends Thread{
14. Table t;
15. MyThread1(Table t){
16. this.t=t;
17. }
18. public void run(){
19. t.printTable(5);
20. }
21.
22. }
23. class MyThread2 extends Thread{
24. Table t;
25. MyThread2(Table t){
26. this.t=t;
27. }
28. public void run(){
29. t.printTable(100);
30. }
31. }
32.
33. public class TestSynchronization2{
34. public static void main(String args[]){
35. Table obj = new Table();//only one object
36. MyThread1 t1=new MyThread1(obj);
37. MyThread2 t2=new MyThread2(obj);
38. t1.start();
39. t2.start();
40. }
41. }

Synchronized block in java


Synchronized block can be used to perform synchronization on any specific resource of the
method.
Suppose you have 50 lines of code in your method, but you want to synchronize only 5 lines, you
can use synchronized block.
If you put all the codes of the method in the synchronized block, it will work same as the
synchronized method.
Points to remember for Synchronized block

o Synchronized block is used to lock an object for any shared resource.


o Scope of synchronized block is smaller than the method.

class Table{
o
o void printTable(int n){
o synchronized(this){//synchronized block
o for(int i=1;i<=5;i++){
o System.out.println(n*i);
o try{
o Thread.sleep(400);
o }catch(Exception e){System.out.println(e);}
o }
o }
o }//end of the method
o }
o
o class MyThread1 extends Thread{
o Table t;
o MyThread1(Table t){
o this.t=t;
o }
o public void run(){
o t.printTable(5);
o }
o
o }
o class MyThread2 extends Thread{
o Table t;
o MyThread2(Table t){
o this.t=t;
o }
o public void run(){
o t.printTable(100);
o }
o }
o
o public class TestSynchronizedBlock1{
o public static void main(String args[]){
o Table obj = new Table();//only one object
o MyThread1 t1=new MyThread1(obj);
o MyThread2 t2=new MyThread2(obj);
o t1.start();
o t2.start();
o }
o }
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.I want no interference between t1 and t3 or t2 and t4.Static synchronization solves
this problem.
1. class Table{
2.
3. synchronized static void printTable(int n){
4. for(int i=1;i<=10;i++){
5. System.out.println(n*i);
6. try{
7. Thread.sleep(400);
8. }catch(Exception e){}
9. }
10. }
11. }
12.
13. class MyThread1 extends Thread{
14. public void run(){
15. Table.printTable(1);
16. }
17. }
18.
19. class MyThread2 extends Thread{
20. public void run(){
21. Table.printTable(10);
22. }
23. }
24.
25. class MyThread3 extends Thread{
26. public void run(){
27. Table.printTable(100);
28. }
29. }
30. class MyThread4 extends Thread{
31. public void run(){
32. Table.printTable(1000);
33. }
34. }
35.
36. public class TestSynchronization4{
37. public static void main(String t[]){
38. MyThread1 t1=new MyThread1();
39. MyThread2 t2=new MyThread2();
40. MyThread3 t3=new MyThread3();
41. MyThread4 t4=new MyThread4();
42. t1.start();
43. t2.start();
44. t3.start();
45. t4.start();
46. }
47. }

Need of Synchronization

To understand the need for synchronization, let’s begin with a simple example that does not use
it—but should. The following program has three simple classes. The first one, Callme, has a
single method named call( ). The call( ) method takes a String parameter called msg.
This method tries to print the msg string inside of square brackets. The interesting thing to notice
is that after call( ) prints the opening bracket and the msg string, it calls Thread .sleep(1000),
which pauses the current thread for one second.
The constructor of the next class, Caller, takes a reference to an instance of the Callme class and
a String, which are stored in target and msg, respectively. The constructor also creates a new
thread that will call this object’s run( ) method. The thread is started immediately.
The run( ) method of Caller calls the call( ) method on the target instance of Callme, passing in
the msg string. Finally, the Synch class starts by creating a single instance of Callme, and three
instances of Caller, each with a unique message string. The same instance of Callme is passed to
each Caller.

// This program is not synchronized.


class Callme {
void call(String msg) {
System.out.print("[" + msg);
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
System.out.println("Interrupted");
}
System.out.println("]");
}
}
class Caller implements Runnable {
String msg;
Callme target;
Thread t;
public Caller(Callme targ, String s) {
target = targ;
msg = s;
t = new Thread(this);
t.start();
}
public void run() {
target.call(msg);
}
}
class Synch {
public static void main(String args[]) {
Callme target = new Callme();
Caller ob1 = new Caller(target, "Hello");
Caller ob2 = new Caller(target, "Synchronized");
Caller ob3 = new Caller(target, "World");
// wait for threads to end
try {
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch(InterruptedException e) {
System.out.println("Interrupted");
}
}
}
Here is the output produced by this program:
Hello[Synchronized[World]
]
]

To fix the preceding program, you must serialize access to call( ). That is, you must restrict its
access to only one thread at a time. To do this, you simply need to precede call( )’s definition
with the keyword synchronized, as shown here:
class Callme {
synchronized void call(String msg) {

This prevents other threads from entering call( ) while another thread is using it. After
synchronized has been added to call( ), the output of the program is as follows:
[Hello]
[Synchronized]
[World]

Inter-thread communication in Java


o Multithreading replaces event loop programming by dividing your tasks into discrete,
logical units. Threads also provide a secondary benefit: they do away with polling.
o Polling is usually implemented by a loop that is used to check some condition repeatedly.
Once the condition is true, appropriate action is taken. This wastes CPU time.
o For example, consider the classic queuing problem, where one thread is producing some
data and another is consuming it. To make the problem more interesting, suppose that the
producer has to wait until the consumer is finished before it generates more data.
o In a polling system, the consumer would waste many CPU cycles while it waited for the
producer to produce. Once the producer was finished, it would start polling, wasting more
CPU cycles waiting for the consumer to finish, and so on. Clearly, this situation is
undesirable.

o To avoid polling, Java includes an elegant interprocess communication mechanism via


the wait( ), notify( ), and notifyAll( ) methods. These methods are implemented as final
methods in Object, so all classes have them.
o Inter-thread communication or Co-operation is all about allowing synchronized
threads to communicate with each other.
o 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.
o It is implemented by following methods of Object class:
o wait()
o notify()
o notifyAll()

1) 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.

The current thread must own this object's monitor, so it must be called from the synchronized
method only otherwise it will throw exception.

Method Description

public final void waits until object is notified.


wait()throws
InterruptedException

public final void waits for the specified amount of time.


wait(long
timeout)throws
InterruptedException

2) 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. Syntax:

public final void notify()

3) notifyAll() method

Wakes up all threads that are waiting on this object's monitor. Syntax:

public final void notifyAll()

Difference between wait and sleep?


Let's see the important differences between wait and sleep methods.

wait() sleep()

wait() method releases sleep() method doesn't release the lock.


the lock

is the method of Object is the method of Thread class


class

is the non-static is the static method


method

is the non-static is the static method


method

should be notified by after the specified amount of time, sleep is completed.


notify() or notifyAll()
methods

Let’s now work through an example that uses wait( ) and notify( ). To begin, consider the
following sample program that incorrectly implements a simple form of the producer/ consumer
problem. It consists of four classes: Q, the queue that you’re trying to synchronize;

Producer, the threaded object that is producing queue entries; Consumer, the threaded object
that is consuming queue entries; and PC, the tiny class that creates the single Q, Producer, and
Consumer.
// An incorrect implementation of a producer and consumer.
class Q {
int n;
synchronized int get() {
System.out.println("Got: " + n);
return n;
}
synchronized void put(int n) {
this.n = n;
System.out.println("Put: " + n);
}
}
class Producer implements Runnable {
Q q;
Producer(Q q) {
this.q = q;
new Thread(this, "Producer").start();
}
public void run() {
int i = 0;
while(true) {
q.put(i++);
}
}
}
class Consumer implements Runnable {
Q q;
Consumer(Q q) {
this.q = q;
new Thread(this, "Consumer").start();
}
public void run() {
while(true) {
q.get();
}
}
}
class PC {
public static void main(String args[]) {
Q q = new Q();
new Producer(q);
new Consumer(q);
System.out.println("Press Control-C to stop.");
}
}
Although the put( ) and get( ) methods on Q are synchronized, nothing stops the producer from
overrunning the consumer, nor will anything stop the consumer from consuming the same queue
value twice.

Thus, you get the erroneous output shown here (the exact output will vary with processor
speed and task load):
Put: 1
Got: 1
Got: 1
Got: 1
Got: 1

Got: 1
Put: 2
Put: 3
Put: 4
Put: 5
Put: 6
Put: 7
Got: 7

As you can see, after the producer put 1, the consumer started and got the same 1 five times in a
row. Then, the producer resumed and produced 2 through 7 without letting the consumer have a
chance to consume them.

The proper way to write this program in Java is to use wait( ) and notify( ) to signal in both
directions, as shown here:

// A correct implementation of a producer and consumer.


class Q {
int n;
boolean valueSet = false;
synchronized int get() {
while(!valueSet)
try {
wait();
} catch(InterruptedException e) {
System.out.println("InterruptedException caught");
}
System.out.println("Got: " + n);
valueSet = false;
notify();
return n;
}
synchronized void put(int n) {
while(valueSet)
try {
wait();
} catch(InterruptedException e) {
System.out.println("InterruptedException caught");
}
this.n = n;
valueSet = true;
System.out.println("Put: " + n);
notify();
}
}
class Producer implements Runnable {
Q q;
Producer(Q q) {
this.q = q;
new Thread(this, "Producer").start();
}
public void run() {
int i = 0;
while(true) {
q.put(i++);
}
}
}
class Consumer implements Runnable {
Q q;
Consumer(Q q) {
this.q = q;
new Thread(this, "Consumer").start();
}
public void run() {
while(true) {
q.get();
}
}
}
class PCFixed {
public static void main(String args[]) {
Q q = new Q();
new Producer(q);
new Consumer(q);
System.out.println("Press Control-C to stop.");
}
}
Inside get( ), wait( ) is called. This causes its execution to suspend until the Producer notifies
you that some data is ready. When this happens, execution inside get( ) resumes.
After the data has been obtained, get( ) calls notify( ). This tells Producer that it is okay to
put more data in the queue. Inside put( ), wait( ) suspends execution until the Consumer has
removed the item from the queue. When execution resumes, the next item of data is put in the
queue, and notify( ) is called. This tells the Consumer that it should now remove it.

Here is some output from this program, which shows the clean synchronous behavior:
Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3
Put: 4
Got: 4
Put: 5
Got: 5

Example of inter thread communication in java


Let's see the simple example of inter thread communication.

1. class Customer{
2. int amount=10000;
3.
4. synchronized void withdraw(int amount){
5. System.out.println("going to withdraw...");
6.
7. if(this.amount<amount){
8. System.out.println("Less balance; waiting for deposit...");
9. try{wait();}catch(Exception e){}
10. }
11. this.amount-=amount;
12. System.out.println("withdraw completed...");
13. }
14.
15. synchronized void deposit(int amount){
16. System.out.println("going to deposit...");
17. this.amount+=amount;
18. System.out.println("deposit completed... ");
19. notify();
20. }
21. }
22.
23. class Test{
24. public static void main(String args[]){
25. final Customer c=new Customer();
26. new Thread(){
27. public void run(){c.withdraw(15000);}
28. }.start();
29. new Thread(){
30. public void run(){c.deposit(10000);}
31. }.start();
32.
33. }}
Output: going to withdraw...
Less balance; waiting for deposit...
going to deposit...
deposit completed...
withdraw completed

Deadlock in java
 Deadlock in java is a part of multithreading.
 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.
 For example, suppose one thread enters the monitor on object X and another thread
enters the monitor on object Y. If the thread in X tries to call any synchronized method
on Y, it will block as expected. However, if the thread in Y, in turn, tries to call any
synchronized method on X, the thread waits forever, because to access X, it would have
to release its own lock on Y so that the first thread could complete. Deadlock is a difficult
error to debug for two reasons:
o In general, it occurs only rarely, when the two threads time-slice in just the right
way.
o It may involve more than two threads and two synchronized objects. (That is,
deadlock can occur through a more convoluted sequence of events than just
described.)
 To understand deadlock fully, it is useful to see it in action. The next example creates two
classes, A and B, with methods foo( ) and bar( ), respectively, which pause briefly before
trying to call a method in the other class. The main class, named Deadlock, creates an A
and a B instance, and then starts a second thread to set up the deadlock condition. The
foo( ) and bar( ) methods use sleep( ) as a way to force the deadlock condition to occur.
// An example of deadlock.
class A {
synchronized void foo(B b) {
String name = Thread.currentThread().getName();
System.out.println(name + " entered A.foo");
try {
Thread.sleep(1000);
} catch(Exception e) {
System.out.println("A Interrupted");
}
System.out.println(name + " trying to call B.last()");
b.last();
}
synchronized void last() {
System.out.println("Inside A.last");
}
}
class B {
synchronized void bar(A a) {
String name = Thread.currentThread().getName();
System.out.println(name + " entered B.bar");
try {
Thread.sleep(1000);
} catch(Exception e) {
System.out.println("B Interrupted");
}
System.out.println(name + " trying to call A.last()");
a.last();
}
synchronized void last() {
System.out.println("Inside A.last");
}
}
class Deadlock implements Runnable {
A a = new A();
B b = new B();
Deadlock() {
Thread.currentThread().setName("MainThread");
Thread t = new Thread(this, "RacingThread");
t.start();
a.foo(b); // get lock on a in this thread.
System.out.println("Back in main thread");
}
public void run() {
b.bar(a); // get lock on b in other thread.
System.out.println("Back in other thread");
}
public static void main(String args[]) {
new Deadlock();
}
}
When you run this program, you will see the output shown here:
MainThread entered A.foo
RacingThread entered B.bar
MainThread trying to call B.last()
RacingThread trying to call A.last()

Because the program has deadlocked, you need to press CTRL-C to end the program. You can
see a full thread and monitor cache dump by pressing CTRL-BREAK on a PC . You will see
that RacingThread owns the monitor on b, while it is waiting for the monitor on a. At the same
time, MainThread owns a and is waiting to get b.

Java Inner Classes


 Java inner class or nested class is a class which is declared inside the class or interface.
 We use inner classes to logically group classes and interfaces in one place so that it can
be more readable and maintainable.
 Additionally, it can access all the members of outer class including private data members
and methods.

Syntax of Inner class

1. class Java_Outer_class{
2. //code
3. class Java_Inner_class{
4. //code
5. }
6. }

Advantage of java inner classes


There are basically three advantages of inner classes in java. They are as follows:

1) Nested classes represent a special type of relationship that is it can access all the
members (data members and methods) of outer classincluding private.

2) Nested classes are used to develop more readable and maintainable code because it
logically group classes and interfaces in one place only.

3) Code Optimization: It requires less code to write.


Difference between nested class and inner class in Java

Inner class is a part of nested class. Non-static nested classes are known as inner classes.

Types of Nested classes

There are two types of nested classes non-static and static nested classes.The non-static nested
classes are also known as inner classes.

o Non-static nested class (inner class)


1. Member inner class
2. Anonymous inner class
3. Local inner class
o Static nested class

Type Description

Member Inner Class A class created within class and outside method.

Anonymous Inner Class A class created for implementing interface or extending


class. Its name is decided by the java compiler.

Local Inner Class A class created within method.

Static Nested Class A static class created within class.

Nested Interface An interface created within class or interface.

Java Member inner class example


In this example, we are creating msg() method in member inner class that is accessing the private
data member of outer class.

1. class TestMemberOuter1{
2. private int data=30;
3. class Inner{
4. void msg(){System.out.println("data is "+data);}
5. }
6. public static void main(String args[]){
7. TestMemberOuter1 obj=new TestMemberOuter1();
8. TestMemberOuter1.Inner in=obj.new Inner();
9. in.msg();
10. }
11. }

Output:

data is 30

You might also like