Multithreading Concept in Java

MULTITHREADING in Java : it is a process of executing two or more threads simultaneously to maximum utilization of CPU.
Or
Multithreading  is a process of executing multiple threads simultaneously.

A thread is a lightweight sub-process, the smallest unit of processing.


There are two types of thread – 


user level thread :
These threads are managed by users.

Kernel level (daemon thread) :-
These threads are managed by operating system.
Threads are used when we want to clean the application and are used in the background.


Advantages of Java Multithreading

1) It doesn't block the users .(provides efficient communication between users)

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

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

4.Threads minimize the context switching time.


Life Cycle of a Thread(Thread states) :


A thread goes through various stages in its life cycle. For example, a thread is born, started, runs, and then dies. The following diagram shows the complete life cycle of a thread.

1. Newborn State:
When we create a thread object, the thread is born and is said to be in newborn
state. The thread is not yet scheduled for running.

Or
A thread begins its life cycle in the new state. It remains in this state until the start() method is called on it.
At this state, we can do only one of the following things with it:
1. Schedule it for running using start() method.
2. Kill it using stop( ) method.
If scheduled, it moves to runnable state. If we attempt to use any other method at this
state, an exception will be thrown.

2. Runnable State:
After invocation of start() method on new thread, the thread becomes Runnable.
Or
The runnable state means that the thread is ready for execution and is waiting for
the availability of the processor. That is, the thread has joined the queue of threads that are
waiting for execution. If all threads are of equal priority, then they are given time slots for
execution in round robin fashion.
The thread that relinquishes control joins the queue at the end and again waits for
its run. However, if we want a thread to relinquish control to another thread of equal
priority before its turn comes, it can do so by invoking the yield() method.


3. Running State:
A thread is in running state if the thread scheduler has selected it.
Or
Running means that the processor has given its time to the thread for its
execution.
A running thread may relinquish its   control in one of the following situations:

1.Its time-slice is over.

2.It is pre-empted by a higher priority thread.

3.It yields i.e. voluntarily relinquishes control.

4.It has completed its execution.

5.It is stopped by some other thread.

6.It has been suspended using suspend() method. A suspended thread can be
revived by using the resume() method. This approach is useful when we want to suspend a thread for some time due to certain reason, but do not want to kill it.

7.It has been told to wait until some event occurs. This is done using the wait()
method. The thread can be scheduled to run again using the notify() method.

8.It is performing some I/O operation.


4.Blocked State:
A thread is said to be blocked when it is prevented form entering into the
runnable state and subsequently the running state. This happens when the thread is
suspended, sleeping or waiting in order to satisfy certain requirements. A blocked thread is
considered “not runnable” but not dead and therefore fully qualified to run again.

Or
A thread is in waiting state if it waits for another thread to perform a task. In this stage the thread is still alive.


5.Terminated(Dead)  state :  A thread enter the terminated state when it complete its task.
thread is Dead when it finishes its execution or is stopped (killed) by another thread.
Or
A running thread ends its life when it has
completed executing its run() method. It has a natural death. However, we kill it by
sending the stop message to it at any state thus causing a premature death. A thread can be killed as soon as it is born, or while it is running, or even when it is in “not runnable”
(blocked condition).


How to Achieve Multithreading ?
Or
Thread creation :
Threads can be created by using two mechanisms :
1. Extending the Thread class
2. Implementing the Runnable Interface


Method 1: Thread creation by extending Thread class
Another way to create a thread is by creating a new class that extends the Thread, then it overrides the run() method and then it creates an instance of that class. The run() method is executed when you call start() method.


The procedure for creating threads based on the Thread Class is as follows:

1. A class extending the Thread class overrides the run() method from the Thread
class to define the code executed by the thread.
2. This subclass may call a Thread constructor explicitly in its constructors to
initialize the thread, using the super() call.
3. The start() method inherited from the Thread class is invoked on the object of
the class to make the thread eligible for running.


Program :
Illustrate creation of thread by extending Thread class.


import java.lang.Thread;
class A extends Thread
{
public void run()
{
System.out.println("thread A is started:");
for(int i=1;i<=5;i++)
{
System.out.println("\t from thread A:i="+i);
}
System.out.println("exit from thread A:");
}
}
class B extends Thread
{
public void run()
{
System.out.println("thread B is started:");
for(int j=1;j<=5;j++)
{
System.out.println("\t from thread B:j="+j);
}
System.out.println("exit from thread B:");
}
}
class C extends Thread
{
public void run()
{
System.out.println("thread C is started:");
for(int k=1;k<=5;k++)
{
System.out.println("\t from thread C:k="+k);
}
System.out.println("exit from thread C:");
}
}
class Threadtest
{
public static void main(String arg[])
{
new A().start();
new B().start();
new C().start();
}
}


Output:
thread A is started:
thread B is started:
thread C is started:
from thread A:i=1
from thread B:j=1
from thread C:k=1
from thread A:i=2
from thread B:j=2
from thread C:k=2
from thread A:i=3
from thread B:j=3
from thread C:k=3
from thread A:i=4
from thread B:j=4
from thread C:k=4
from thread A:i=5
from thread B:j=5
from thread C:k=5
exit from thread A:
exit from thread B:
exit from thread C:

Or

Program 2:
WAP in Java that creates three threads. First thread displays Good Morning every one second, the second thread displays Hello every two seconds and the third thread displays Welcome every three seconds.


class A extends Thread
{
     synchronized public void run()
     {
    try
    {
        while(true)
        {
           sleep(1000);
           System.out.println("good morning");
        }
    }
    catch(Exception e)
    { }
      }
}
class B extends Thread
{
      synchronized public void run()
      {
    try
    {
        while(true)
        {
        sleep(2000);
        System.out.println("hello");
        }
        }
      catch(Exception e)
    { }
      }
}
class C extends Thread
{
     synchronized public void run()
     {
    try
    {
        while(true)
        {
            sleep(3000);
            System.out.println("welcome");
        }
    }
    catch(Exception e)
    { }
     }
}
class ThreadDemo
{
    public static void main(String args[])
    {
        A t1=new A();
        B t2=new B();
        C t3=new C();
        t1.start();
        t2.start();
        t3.start();
    }
}


Output:
good morning
good morning
hello
good morning
welcome
good morning
hello
good morning
welcome
hello
good morning
good morning
hello
good morning
welcome
good morning
hello
good morning
good morning
hello
welcome
good morning



Method 2: Thread creation by implementing Runnable Interface:


The Runnable interface should be implemented by any class whose instances are intended to be
executed by a thread.

The simplest way to create a thread is to create a class by implementing the Runnable interface. Runnable interface have only one method named run().
To do this we need a class which implements a single method called run( ), which is declared like this:
public void run().


The procedure for creating threads based on the Runnable interface is as follows:

1. A class implements the Runnable interface, providing the run() method that will
be executed by the thread. An object of this class is a Runnable object.
2. An object of Thread class is created by passing a Runnable object as argument to
the Thread constructor. The Thread object now has a Runnable object that
implements the run() method.
3. The start() method is invoked on the Thread object created in the previous
step. The start() method returns immediately after a thread has been spawned.


Program :
Illustrate thread creation by implementing runnable interface.

import java.lang.Runnable;
class X implements Runnable
{
public void run()
{
for(int i=1;i<10;i++)
{
System.out.println("\t Thread X:"+i);
}
System.out.println("End of Thread X");
}
}
class Runnabletest
{
public static void main(String arg[])
{
X R=new X();
Thread T=new Thread(R);
T.start();
}
}


Output:
Thread X:1
Thread X:2
Thread X:3
Thread X:4
Thread X:5
Thread X:6
Thread X:7
Thread X:8
Thread X:9
End of Thread X


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.


Constructors of Thread class:

-Thread()

-Thread(String name)

-Thread(Runnable r)

- Thread(Runnable r,String name)


Thread Class Methods :

Commonly used methods of Thread class:


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


2. public void start(): starts the execution of the thread.JVM calls the run() method on the thread.


3. public void sleep(long miliseconds): Causes the currently executing thread to sleep (temporarily
cease execution) for the specified number of milliseconds.


4. public void join(): waits for a thread to die.
Wait for a thread to end.


5. public void join(long miliseconds): waits for a thread to die for the specified miliseconds.


6. public int getPriority(): returns the priority of the thread.


7. public int setPriority(int priority): changes the priority of the thread.


8. public String getName(): returns the name of the thread.
we cannot override  getName() function, because they are declared final in Thread Class.


9. public void setName(String name): changes the name of the thread.
we cannot override setName()  function, because they are declared final in Thread Class.


10. public Thread currentThread(): returns the reference of currently executing thread.


11. public int getId(): returns the id of the thread.


12. public Thread.State getState(): returns the state of the thread.


13. public boolean isAlive(): tests if the thread is alive.


14. public void yield(): causes the currently executing thread object to temporarily pause and allow other threads to execute.


15. public void suspend(): is used to suspend the thread(depricated).


16. public void resume(): is used to resume the suspended thread(depricated).


17. public void stop(): is used to stop the thread(depricated).


18. public boolean isDaemon(): tests if the thread is a daemon thread.


19. public void setDaemon(boolean b): marks the thread as daemon or user thread.


20. public void interrupt(): interrupts the thread.


21. public boolean isInterrupted(): tests if the thread has been interrupted.


22. public static boolean interrupted(): tests if the current thread has been interrupted.

Thread Priorities:

In Java, when we create a thread, always a priority is assigned to it. In a Multithreading environment, the processor assigns a priority to a thread scheduler. The priority is given by the JVM or by the programmer itself explicitly. Each thread have a priority. Priorities are represented by a number between 1 and 10. There are three variables which are static to define priority in a Thread Class.

Note: Thread priorities cannot guarantee that a higher priority thread will always be executed first than the lower priority thread. The selection of the threads for execution depends upon the thread scheduler which is platform dependent.

3 constants defined in Thread class:

1.MAX_PRIORITY :
It represents the maximum priority that a thread can have.
The value of MAX_PRIORITY is 10.

2.MIN_PRIORITY :
It represents the minimum priority that a thread can have.
The value of MIN_PRIORITY is 1.

3.NORM_PRIORITY :
It represents the default priority that a thread can have.
Default priority of a thread is 5 (NORM_PRIORITY).
The value for this is 0.


Program :
illustrates how priority is assigned.

import java.lang.Thread;
class A extends Thread
{
public void run()
{
System.out.println("thread A is started:");
for(int i=1;i<=5;i++)
{
System.out.println("\t from thread A:i="+i);
}
System.out.println("exit from thread A:");
}
}
class B extends Thread
{
public void run()
{
System.out.println("thread B is started:");
for(int j=1;j<=5;j++)
{
System.out.println("\t from thread B:j="+j);
}
System.out.println("exit from thread B:");
}
}
class C extends Thread
{
public void run()
{
System.out.println("thread C is started:");
for(int k=1;k<=5;k++)
{
System.out.println("\t from thread C:k="+k);
}
System.out.println("exit from thread C:");
}
}
class ThreadPriority
{
public static void main(String arg[])
{
System.out.println("Main thread started");
A ta=new A();
B tb=new B();
C tc=new C();
ta.setPriority(Thread.MAX_PRIORITY); 
 tb.setPriority(ta.getPriority()+1);
 tc.setPriority(Thread.MIN_PRIORITY);
    ta.start();
tb.start();
tc.start();
try
  {
  ta.join();
tb.join();
t3.join();
   }
   catch(InterruptedException e){}     
System.out.println("Main Thread Finished");
}
}


Thread interrupting :

Thread interruption is a way in which a thread who is either in sleeping or waiting state can be made to stop sleeping or waiting by throwing InterruptedException. If thread is not in sleeping or waiting state then calling thread interruption methods will not affect the program and programs will execute normally it just sets the interrupt flag to true.
A running thread can be interrupted by calling interrupt() method on it.

The Thread class provides three interrupt methods.

void interrupt() - Interrupts the thread.


static boolean interrupted() - Tests whether the current thread has been interrupted.


boolean isInterrupted() - Tests whether the thread has been interrupted.


Program :Interrupting a thread that works normally : 

class A extends Thread {
    public void run()
    {
        for (int i = 0; i < 5; i++)
            System.out.println(i);
    }
    public static void main(String args[])
    {
        A t1 = new A();
        t1.start();
        t1.interrupt();
    }
}

Output:
0
1
2
3
4


Synchronization:

Java provides high-level concepts for synchronization in order to control access to shared resources.
It is capability to control the access of multiple threads to any shared resource.

Threads share the same memory space, that is, they can share resources. However, there are critical situations where it is desirable that only one thread at a time has access to a shared resource.
For example, crediting and debiting a shared bank account concurrently amongst several users without proper discipline, will jeopardize the integrity of the account data.

 

Uses of synchronization :

-To restrict thread interleaving.
-To prevent consistency problem.


Types of Thread Synchronization :


There are two types of thread synchronization


1. mutual exclusion:Mutual Exclusive helps keep threads from interfering with one another while sharing data.
   a. Synchronized method.
   b. Synchronized block.


2. inter-thread communication.(cooperation) : 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()
notify()
notifyAll()


Program :
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();
  }
  } 
   class Test
{  
public static void main(String args[])
{  
final Customer c=new Customer(); 
 new Thread()
{  
public void run()
{
c.withdraw(15000);} 
 }.start();  
new Thread()
{  public void run(){
c.deposit(10000);}
  }.start(); 

   }
}  


Join Concept in multithreading :

The join() method is used to hold the execution of currently running thread until the specified thread is dead(finished execution).
join() method which allows one thread to wait until another thread completes its execution. 


Why we use join() method?

In normal circumstances we generally have more than one thread, thread scheduler schedules the threads, which does not guarantee the order of execution of threads.

Syntax :
public final void join();


Program :

Illustrate thread join Concept. 


import java.lang.Thread;
class A extends Thread
{
public void run()
{
System.out.println("thread A is started:");
for(int i=1;i<=5;i++)
{
System.out.println("\t from thread A:i="+i);
}
System.out.println("exit from thread A:");
}
}
class B extends Thread
{
public void run()
{
System.out.println("thread B is started:");
for(int j=1;j<=5;j++)
{
System.out.println("\t from thread B:j="+j);
}
System.out.println("exit from thread B:");
}
}
class C extends Thread
{
public void run()
{
System.out.println("thread C is started:");
for(int k=1;k<=5;k++)
{
System.out.println("\t from thread C:k="+k);
}
System.out.println("exit from thread C:");
}
}
class Threadjoin
{
public static void main(String arg[])
{
System.out.println("Main thread started");
A ta=new A();
B tb=new B();
C tc=new C();
    ta.start();
    tb.start();
try
  {
  ta.join();
tb.join();
   }
   catch(InterruptedException e){}     
tc.start();
System.out.println("Main Thread Finished");
}
}



Producer - consumer problem :

The producer-consumer problem (also known as the bounded-buffer problem) is a classic example of a multi-process synchronization problem. The problem describes two processes, the producer and the consumer, which share a common, fixed-size buffer used as a queue.

The producer’s job is to generate data, put it into the buffer, and start again.
At the same time, the consumer is consuming the data (i.e. removing it from the buffer), one piece at a time.

Problem
To make sure that the producer won’t try to add data into the buffer if it’s full and that the consumer won’t try to remove data from an empty buffer.

Solution
The producer is to either go to sleep or discard data if the buffer is full. The next time the consumer removes an item from the buffer, it notifies the producer, who starts to fill the buffer again. In the same way, the consumer can go to sleep if it finds the buffer to be empty. The next time the producer puts data into the buffer, it wakes up the sleeping consumer.

Write a java program that correct implements of producer consumer program.
SOURCE CODE:
class Q
{
int n;
boolean valueSet=false;
synchronized int get()
{
if(!valueSet)
try
{
wait();
}
catch(InterruptedException e)
{
System.out.println("Interrupted Exception caught");
}
System.out.println("Got:"+n);
valueSet=false;
notify();
return n;
}
synchronized void put(int n)
{
if(valueSet)
try
{
wait();
}
catch(InterruptedException e)
{
System.out.println("Interrupted Exception 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 ProdCons
{
public static void main(String[] args)
{
Q q=new Q();
new Producer(q);
new Consumer(q);
System.out.println("Press Control-c to stop");
}
}


OUTPUT:
Put:1 Got:1
Put:2 Got:2
Put:3 Got:3
Put:4 Got:4
Put:5 Got:5
Put:6 Got:6
Put:7 Got:7
Put:8 Got:8
Put:9 Got:9


Comments

Popular posts from this blog

Applets - Inheritance hierarchy for applets, differences between applets and applications, life cycle of an applet, passing parameters to applets, applet security issues.

Control Statements:Selection statement ,Iteration statement and Jump statement in Java

Write a java program to demonstrate static variable, methods, blocks.