==============
Multi Threading
==============
Task : Work
Single Tasking : Performing only one task at a time is called as Single Tasking
Ex:
1) Explain the topic
2) Dictate the notes
3) Ask questions
-> If we perform single tasking then it will take lot of time to complete all our
work.
Multi Tasking : Performing multiple tasks at a time is called as Multi Tasking
Ex:
1) Walking & listening music
2) Speaking and Writing
3) Reading book & eating
-> If we perform multi tasking then we complete multiple works at a time.
-> Multi Tasking we can achieve in 2 ways
1) Process Based Multi Tasking
Ex: Windows OS
2) Thread Based Multi Tasking
-> To execute our program logics paralelly then we need to go for Thread Based
Multi Tasking
-> Using Thread Based Multi Tasking our program can complete the work quickly
-> To implement Thread Based Multi Tasking we will use Multi Threading
-> Java Supports Multi Threading
=============================
Use case to go for Multi Threading
=============================
1) Send sms to all customers at a time
2) Send Email to all customers at a time
3) Generate & Send Bank Statements to all customers in email
Note: The main aim of Multi Tasking is used execute our program logic paralelly so
that we can complete more work in less time.
-> For Every Java program execution, JVM will create one thread by default. That
thread is called as Main thread.
// Java Program to get the details of Main thread
public class Demo {
public static void main(String... args) {
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName()); // main
}
}
Note: Thread is a predefined class available in java.lang package. In Thread class
we have a static method currentThread ( ).
===================
User Defined Threads
===================
-> In Java we can create Thread in 2 ways
1) By extending Thread class
2) By Implementing Runnable interface
// Java program to create user defined thread using Thread class
public class Demo extends Thread {
public void run() {
System.out.println("run () method called...");
}
public static void main(String... args) {
Demo d = new Demo();
Thread t = new Thread(d);
t.start();
}
}
// Java program to create the thread using Runnable interface
public class Demo implements Runnable {
public void run() {
System.out.println("run () method called...");
}
public static void main(String... args) {
Demo d = new Demo();
Thread t = new Thread(d);
t.start();
}
}
===================================================================================
===============
Q) What is the difference between extending Thread class and implementing Runnable
interface, which is recommended ?
===================================================================================
===============
-> If we extend properties from Thread class then we can't extend properties from
any other class because java doesn't support mulitple inheritence. (We are closing
gate for Inheritence)
-> If we implement Runnable interface then in future we can extend properties from
any class based on requirement. (Our gate is open for inheritence)
Note: Implementing Runnable interface is always recommended.
=======================
What is Thread Schedular
=======================
-> Thread Schedular is a program in the JVM which is responsible to schedule
Threads execution and resources allocation required for the thread.
-> When we call start ( ) method then Thread Schedular will start its operation.
1) Allocating Resources
2) Thread Scheduling
3) Thread Execution by calling run ( ) method
================================
start ( ) method vs run ( ) method
================================
-> To start thread execution we will call start ( ) method
t.start ( )
-> once start ( ) method is called then Thread Schedular will come into picture to
execute our thread
-> start ( ) method will call run ( ) method internally
-> inside run ( ) method we will write the logic which should be executed by the
thread.
=======================================================
Can we call run ( ) method directley without calling start ( ) method
========================================================
-> Yes, we can call run ( ) method directley but it will execute like a normal
method (there is no use) by "main" thread.
-> If we want to execute run ( ) method as a thread method then we should call
start ( ) method then internally it will call run ( ) method (Thread Schedular will
take care of thread execution)
public class Demo implements Runnable {
public void run() {
System.out.println("run () method started...");
Thread t = Thread.currentThread();
System.out.println(t.getName());
System.out.println("run () method ended...");
}
public static void main(String... args) {
Demo d = new Demo();
Thread t = new Thread(d);
//t.start();
// t.run();
}
}
=> If we call start ( ) method then run ( ) method will be executed by our user
defined thread (we can see thread name as Thread-0)
=> if we call run ( ) method then run ( ) method will be executed by "main" thread
(we can see thread name as main)
======================
What is Thread Life Cycle
======================
-> Thread Life cycle contains several phases of Thread execution
1) New
2) Runnable
3) Running
4) Blocked
5) Terminated
New: A thread begins its life cycle in the new state. Thread remains in the new
state until we will call start ( ) method.
Runnable : After calling start ( ) method, thread comes from new state to runnable
state.
Running : A thread comes to running state when Thread Schedular will pick up that
thread for execution.
Blocked : A thread is in waiting state if it waits for another thread to complete
its task.
Terminated : A thread enters into terminated state once it completes its task.
// Java Program on Thread Sleep
package in.ashokit;
public class Demo implements Runnable {
public void run() {
System.out.println("run () method started...");
try {
Thread.sleep(5000); // blocked state
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("run () method ended...");
}
public static void main(String... args) {
Demo d = new Demo();
Thread t = new Thread(d); // new state
t.start(); // runnable state
}
}
// Java program to start mutliple threads to perform same activity
package in.ashokit;
public class Demo implements Runnable {
public void run() {
System.out.println("run () method started..." +
Thread.currentThread().getName());
try {
Thread.sleep(15000); // blocked state
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("run () method ended..." +
Thread.currentThread().getName());
}
public static void main(String... args) {
Demo d = new Demo();
Thread t1 = new Thread(d);
t1.setPriority(Thread.MAX_PRIORITY); // 10
t1.setName("Thread-1");
Thread t2 = new Thread(d);
t2.setPriority(Thread.NORM_PRIORITY); // 5
t2.setName("Thread-2");
Thread t3 = new Thread(d);
t3.setPriority(Thread.MIN_PRIORITY); // 1
t3.setName("Thread-3");
t1.start(); // runnable state
t2.start(); // runnable state
t3.start(); // runnable state
}
}
Note: We shouldn't start one thread more than one time.
public static void main(String... args) {
Demo d = new Demo();
Thread t1 = new Thread(d);
t1.start();
t1.start(); // java.lang.IllegalThreadStateException
}
=================
Callable Interface
=================
-> This interface introduced in java 1.5
-> Using Callable interface also we can create the Thread
-> This interface contains call ( ) method.
Syntax:
public Object call ( )
====================================================
What is the difference between Runnable & Callable interfaces
====================================================
-> Runnable is a functional interface which contains run ( ) method
-> Callable is a functional interface which contains call ( ) method
-> Runnable run ( ) method returns void (no return type)
-> Callable call ( ) method returns Object
-> Runnable interface present in java.lang package
-> Callable interface present in java.util.concurent package
==============================
ExecutorService
==============================
-> Executor Service introduced in java 1.5v
-> Using ExecutorService we can implement multi threading
-> Using Executors we can create thread pool
-> Using Executor Service we can submit tasks to pool of threads.
-> ExecutorService will re-use threads available in the pool to complete all
submitted tasks.
// Java Program on Executor Service with Callable interface
package in.ashokit;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Demo implements Callable {
public Object call() throws Exception {
System.out.println("call ( ) - method executed...");
return "success";
}
public static void main(String[] args) throws Exception {
Demo d = new Demo();
ExecutorService exService = Executors.newFixedThreadPool(10);
for (int i = 1; i <= 15; i++) {
Future submit = exService.submit(d);
System.out.println(submit.get().toString());
}
exService.shutdown();
}
}
=============
Daemon Thread
=============
We have 3 types of threads in java
1) Default thread created by JVM ( main thread )
2) User Defined Threads ( Thread class, Runnable interface, Callable interface )
3) Daemon Threads
Note: The thread which runs in the background is called as Dameon Thread. Daemon
Threads also called as low priority threads.
Ex: Garbage Collector is a daemon thread
-> We can make our thread as Daemon Thread using setDaemon( ) method
// Java Program To Make thread as Daemon
package in.ashokit;
public class Demo implements Runnable {
@Override
public void run() {
if (Thread.currentThread().isDaemon()) {
System.out.println("Daemon Thread Executed...");
} else {
System.out.println("Normal Thread Executed...");
}
public static void main(String[] args) {
Demo d = new Demo();
Thread t1 = new Thread(d);
t1.setDaemon(true);
t1.start();
}
}
-> When JVM reaches end of main method, it will terminate our program. If JVM
founds Daemon thread running it terminates that daemon thread and then it will
shutdown the program.
-> JVM will not care about Daemon Threads running status to stop the program
execution.
==============
Synchronization
==============
String ----> Immutable class
StringBuffer ----> Mutable class & synchronized class (Thread safe class)
StringBuilder ---> Mutable class & not-synchronized class (Not Thread Safe class)
Synchronized means Thread safe ===> Only one thread can access the object /
resource at a time
Not-Synchronized means Not Thread Safe => Multiple threads can access same
resource / object at a time
public class MovieTicketBooking {
int avilableTickets = 100;
public void run ( ) {
if ( availableTickets > 0 ) {
// logic to bookTicket;
-- avilableTickets ;
}
}
psvm ( ) {
Thread t1 = new Thread();
Thread t2 = new Thread();
Threa t20 = new Thread();
t1..... t20 ---start
}
}
-> In the program, multiple threads are trying to book tickets at a time
Note: If multiple threads access the same object at a time then there is a chance
of getting data inconsistency problem.
=> To avoid data inconsistency problem, we need to use Synchronization concept
=> Synchronization means allowing only one thread to execute our resource /
object / logic at a time
Note: By Using Synchronization we can achieve Thread Safety but it will slow down
our execution process.
===========================
How to achieve synchronization
===========================
-> Using 'synchronized' keyword we can implement synchronization
-> synchronized keyword we can use at two places
1) At method level
2) At block level
--------------------------------------------
Syntax For Synchronized Block:
--------------------------------------------
public void m1( ){
// pre-logic
synchronized ( object ) {
// imp business logic
}
// post-logic
--------------------------------------------
Syntax For Synchronized Method :
--------------------------------------------
public synchronized void m1( ) {
// important business logic
// Java Program with Synchronized Method
public class Demo implements Runnable {
public synchronized void printNums() {
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + "=> " + i);
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void run() {
printNums();
}
public static void main(String[] args) {
Demo d = new Demo();
Thread t1 = new Thread(d);
t1.setName("Thread-1");
t1.start();
Thread t2 = new Thread(d);
t2.setName("Thread-2");
t2.start();
}
}
Note: In the above program we are starting 2 threads. two threads will access
printNums ( ) method to print the numbers from 1 to 10.
-> If printNums ( ) method having synchronized keyword then two threads will
execute the method sequentially one after other .
-> if we remove synchronized keyword from the printNums ( ) method then two threads
will access that method at a time.
Note: We can see the difference in the output.
==============================================
Working with Threads using Anonymous Implementation
==============================================
package in.ashokit;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyThread {
public static void main(String[] args) {
Thread t1 = new Thread() {
public void run() {
System.out.println("run ( ) method logic-1");
}
};
t1.start();
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("run method() logic-2");
}
};
Thread t2 = new Thread(r);
t2.start();
Callable c = new Callable() {
public Object call() throws Exception {
System.out.println("call( ) method logic - 3");
return null;
}
};
ExecutorService exService = Executors.newFixedThreadPool(1);
exService.submit(c);
}
}
==========
Dead Lock
=========
-> Dead Lock means ambiguity problem among the threads
-> If 2 threads are waiting for each other to release the resources is called as
dead lock.
-> Once we get into dead lock situation then we can't do anything
Ex:
----
Thread-1 holding resource-1 and waiting for resource-2
Thread-2 holding resource-2 and waiting for resource-1
Note:
Thread-1 will not release resource-1 hence thread-2 will be in waiting state
forever for resource-1
Thread-2 will not release resource-2 hence thread-1 will be in waiting state
forever for resource-2
// Java program which will give dead lock
package in.ashokit;
public class DeadLock {
public static void main(String[] args) {
String s1 = "hi";
String s2 = "hello";
Thread t1 = new Thread() {
public void run() {
synchronized (s1) {
System.out.println("Thread-1 locked resource-1");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s2) {
System.out.println("Thread-1 waiting for
resource-2");
}
}
}
};
Thread t2 = new Thread() {
public void run() {
synchronized (s2) {
System.out.println("Thread-2 locked resource-2");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s1) {
System.out.println("Thread-2 waiting for
resource-1");
}
}
}
};
t1.start();
t2.start();
}
}
=============
join ( ) method
=============
-> join ( ) method is used to hold second thread execution until first thread
execution got completed
package in.ashokit;
public class Demo {
public static void main(String[] args) throws Exception {
Thread t1 = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() +
" => " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.setName("Thread-1");
Thread t2 = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() +
" => " + i);
try {
Thread.sleep(100);
Thread.yield();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t2.setName("Thread-2");
t1.start();
t1.join();
t2.start();
}
}
==============
yield ( ) method
===============
-> yield ( ) method is used to give chance for other equal priority threads to
execute
// Java program with yield ( ) method
package in.ashokit;
public class YieldDemo {
public static void main(String[] args) {
Thread producer = new Producer();
Thread consumer = new Consumer();
producer.start();
consumer.start();
}
}
class Producer extends Thread {
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("Producer : Produced Item " + i);
Thread.yield();
}
}
}
class Consumer extends Thread {
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("Consumer : Consumed Item " + i);
Thread.yield();
}
}
}
========================
Inter Thread Communication
========================
-> It is used to establish communication among the threads
-> To achieve inter thread communication we have below 3 methods in Object class
1) wait ( )
2) notify ( )
3) notifyAll ( )
Q) Why these 3 methods available in Object class, why not in Thread class ?
-> If these methods available in Thread class then we have to extend Thread class.
In future we can't extend from any other java class bcz java is against for
Multiple Inheritence.
-> If these methods available in Runnable interface then everybody should implement
these method even if they don't need inter thread communication.
-> To overcome all these problems, java kept these methods in Object class so that
every class will have access for these methods.
// Java Program to establish inter thread communication
package in.ashokit;
public class Customer {
int amount = 10000;
synchronized void withdraw(int amount) {
System.out.println("going to withdraw...");
if (this.amount < amount) {
System.out.println("Less balance; waiting for deposit...");
try {
wait();
} catch (Exception e) {
}
}
this.amount -= amount;
System.out.println("withdraw completed...");
}
synchronized void deposit(int amount) {
System.out.println("going to deposit...");
this.amount += amount;
System.out.println("deposit completed... ");
notify();
}
public static void main(String args[]) {
final Customer c = new Customer();
new Thread() {
public void run() {
c.withdraw(15000);
}
}.start();
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread() {
public void run() {
c.deposit(10000);
}
}.start();
}
}
================================
Multi Threading Summary
=================================
1) What is Multi Tasking
2) What is Multi Threading
3) Advantages of Multi Threading
4) Default Thread in JVM (main)
5) Getting info of main thread ( Thread.currentThread( ) )
6) Creating User Defined Threads
7) By Extending Thread class
8) By Implementing Runnable interface
9) By implementing Callable interface
10) run ( ) method vs call ( )
11) Executor Service
12) run ( ) vs start ( ) method
13) Thread Life Cycle
14) Thread Schedular
15) Synchronization (method & block)
16) What is Thread Safety
17) Thread creation with Anonymous implementation
18) Dead Lock (Java Program to give dead lock)
19) join ( ) method vs yield ( ) method
20) Inter Thread Communication
21) Daemon Threads