MultiThreading in Java
Multi Tasking :
multitasking allows several activities to occur concurrently on the computer
Process-based multitasking
Allows programs(ie processes) to run concurrently on the same computer.
Eg : ie working on MS paint while working on word
Thread based multitasking
Allows part of the same program to run concurrently on the computer
Eg : Ms word printing and formatting text at same time
Thread vs Process
Two threads share the same address space
context switching between the threads is usually less expensive than between process
The cost of communication between threads is very low
Why Multithreading
In a single-threaded Environment only one task is performed at a time
CPU cycles are wasted , for example when waiting for the user input
Multi tasking allows idle CPU time to be in good use
Thread :
A thread is an independent sequential execution with in a program
Many Threads can run concurreently with in a program
At run time threads in a program share common memory space. can therefore share both data and code (i e they are light weight compared to proces
The Main Thread:
When a stand-alone Application is run, a user thread is automatically created to execute the main method of the Application. This Thread is called Main Thread
if no user threads are spawned . the program got terminated when the main method finishes executing
All other Threads are called Child Threads Spawned from the main Thread
The main method then can finish but the Program will keep running untill all user threads have completed
The running enviroment distinguishes between user thread and daemon thread
Calling the setDaemon(boolean) method marks the status of the Thread as either Daemon or User. but this must be done before the thread has started
As long as user thread is alive JVM does not terminate
A Daemon thread is at the mercy of runtime system . if it is stopped if there are no more user threads are running. Thus terminating Program
Thread Creation :
A thread in java is represented by object of thread class
creation of the thread can be done in two ways
Implementing Java.lang.Runnable
Extending Java.lang.Thread class
Creating a Thread in Java
- By extending the Thread Class
class Multithread extends Thread{
public Multithread(String str){
super(str)
}
public void run(){
for(int i=0;i<10;i++){
System.out.println("thread is running..."+Thread.currentThread().getName());
}
}
public static void main(String args[]){
Multithread t1=new Multithread("Thread 1");
t1.start();
}
}
- Implementing the Runnable Interface
class Multithreading implements Runnable{
public void run(){
for(int i=0;i<10;i++){
System.out.println("thread is running...");
}
}
public static void main(String args[]){
Multithreading thread=new Multithreading();
Thread t1 =new Thread(thread); // Using the constructor Thread(Runnable)
t1.start();
}
}
Daemon Thread :
The Thread which executed in Background is called Daemon Thread. once user Thread got executed completely. Then it was at the mercy of the JVM to continue execution or not for Daemon Thread
class MyThread extends Thread{
public void run(){
for(int i=0;i<10;i++){
System.out.println("I am in chaild Threa"+i);
}
}
}
public class Main
{
public static void main(String[] args) {
System.out.println("Hello World");
System.out.println("I am in Main Thread");
MyThread obj=new MyThread();
obj.setDaemon(true);
obj.start();
}
}
Which is the best method to create a Thread and Why
Creating a thread by implementing a Runnable Interface is preferred because java does not support multiple inheritance so by implementing interface we can achieve multiple interface
Implementation of run method using Lambda Expression
public class Main
{
public static void main(String[] args) {
System.out.println("Hello World");
Runnable obj= ()->System.out.println("I am in Thread class using Anonymous inner class....");
Thread thread =new Thread(obj);
thread.start();
}
}
Synchronization :
Threads share the common memory space i e they can share the resources
How ever there are critical situations only one thread should access the resource
class Stack
{
int capacity;
private int arr[];
private int stackTop;
Object lock;
public Stack(int capacity){
arr=new int[capacity];
stackTop=-1;
lock=new Object();
}
public synchronized boolean push(int element){
if(isFull())
return false;
++stackTop;
try{
Thread.sleep(1000);
}catch(Exception e){
}
arr[stackTop]=element;
return false;
}
public synchronized int pop(){
if(isEmpty()){
return Integer.MIN_VALUE;
}
int obj=arr[stackTop];
try{
Thread.sleep(1000);
}catch(Exception e){
}
stackTop--;
return obj;
}
public boolean isEmpty(){
return stackTop<0;
}
public boolean isFull(){
return stackTop==10;
}
}
public class Main
{
public static void main(String[] args) {
Stack stack = new Stack(10);
System.out.println("Main Thread is Starting");
new Thread(()->{
int counter=0;
while(counter<10){
System.out.println("Pushing the element"+stack.push(counter));
counter++;
}
},"Pusher").start();
new Thread(()->{
int counter=0;
while(counter<10){
System.out.println("Popping the element"+stack.pop());
counter++;
}
},"Pusher").start();
}
}
Rules of Synchronization :
A thread must acquire an object lock associated with a shared resource before it enters the shared resource
A run time system ensures that no other thread enters the shared resource if another thread already holds the object lock
If a thread cannot immediately acquire the object lock. it is blocked ie it must wait for the lock available
Synchronization of static method in a class is independent of instance methods of the object class
Race condition :
It occurs when two or more threads simultaneously update the same value (stackTopIndex) as a state, as a consequence leave the value in an undefined or inconsistent state.
The Singleton class :
Only one object is created for that class , if we try to create another object it will return the same object n if its already created, constructor of the class should be private .
class TvSet
{
private static volatile Tvset tvSetInstance=null;
private TvSet(){
System.out.println("I am in Private constructor");
}
public static TvSet getTvSetInstance(){
if(tvSetInstance==null){
Synchronized(TvSet.class){
if(tvSetInstance==null){
tvSetInstance=new TvSet();
}
}
}
return tvSetInstance;
}
}
Volatile Key Word :
if a variable is shared by multiple threads leading to inconsistency, Basically every thread has its own cache. it reads the value from the cache instead of the main memory. for suppose if there is a common variable between the 2 threads if one thread updates the value in its cache. it will reflect in the main memory as well as another thread cache. it will solve the Problem of inconsistency, which can be explained help of the diagram
Producer Consumer Pattern :
we can push items into Queue if there is some empty shells in it
We can pop items from the Queue if there are any items left in the Queue
it can be explained in below code:
public class BlockingQueue
{
private Queue<Integer> queue;
private int capacity;
public BlockingQueue(int cap){
q=new LinkedList<>();
capacity=cap;
}
public boolean add(int item){
synchronized(queue){
while(queue.size()==capacity){
try{
queue.wait(); // adder 1 and adder2
}catch(){
}
}
queue.add(item);
queue.notifyAll();
}
}
public int remove(){
synchronized(queue){
while(queue.size()==0){
try{
queue.wait();
}catch(){
}
}
int element=queue.poll();
queue.notifyAll();
return element;
}
}
}
in the Above code actually threads compete for the common code. in that process suppose if that thread got a chance to execute push method first it will check whether the queue is empty or not. If it's empty it will add and notify other threads or else it will go to wait state now other threads got unblocked and again compete for the common code and vice versa
Thread States
New State: When an instance of a thread class is created then the thread said to be in new state
Runnable State : When a start method is created on new born thread then the Thread is said to be in a Runnable state
In the runnable state, the thread is ready for execution and is waiting for the availability of the processor (CPU time). There are many threads that are ready for execution, they all are waiting in a queue (line).
Running State: Running means Processor (CPU) has allocated time slot to thread for its execution. When the thread scheduler selects a thread from the runnable state for execution, it goes into the running state.
Blocked state: A thread is considered to be in the blocked state when it is suspended, sleeping, or waiting for some time in order to satisfy some condition.
Dead State : When the thread completes its run method its said to be in Dead state