Friday, 7 September 2018

Multithreading


Multithreading

Introduction:

It is one of the important features of Java that allows us to run two different parts of the program concurrently by sharing the common resources of the system.

A Thread is a lightweight component that is similar to a program.

Multithreading is a conceptual programming where a program is divided into two or more processes which can be implemented at the same time in parallel.

Ex:- In a MS-Word we can modify the document on the foreground, at then we can send the job of  printing at the background.

Keypoints:
  1. By default every java program is under the implementation of main
  2. thread.
  3. Each thread has a main and a priority
  4. Threads has to be started explicitly.
  5. Threads can be synchronized.
  6. Threads can be intercommunicated.

Creating Threads:
 A new thread can be created in 2 ways:
1. By extending from Thread Class
2. By implementing a Runnable Interface.

If it requires extending from more than one class, then we have to implement the Runnable interface, since Java classes cannot have two superclass. It depends on the classes we create. Otherwise we can use Thread Class. The Runnable interface has only one method, run().

By extending from Thread Class:

class classname extends Thread
{
            Thread () {  }   // Thread constructor if required
            public void run()
            {
                        -------
                        -------
            }
}

To start the Thread:
For example we take classname is ABC
ABC a=new ABC();
a.start();

Ex:
class ABC extends Thread
{
           
            public void run()
            {
                        System.out.println("Welcome to the concept of Threads");
            }
}
class xx
{
            public static void main(String []args)
            {
                             ABC a=new ABC();
                            Thread t=new Thread(a);
                                    t.start();
           
            }
}         

By implementing a Runnable Interface:

  1. Declare the class as implementing the Runnable interface
  2. Implement the run() method
  3. Create a thread by defining an object that is instantiated from this 'runnable' interface
  4. Call the threads start() method to run the thread.

Ex:
class y
{
int bal=100;
}
class x implements Runnable
{
y p;
int r;
int sleepValue;
x(int a,int b, y g)
{
r=a;
sleepValue=b;
p=g;
}
public void run()
{
if(p.bal>r)
{
System.out.println("fund is available");
p.bal=p.bal-r;
System.out.println("Got it!!!"+Thread.currentThread());
synchronized(p)
{
try
{
Thread.sleep(sleepValue);
}
catch (Exception e){}
}
else
{
System.out.println("Insufficient bal "+Thread.currentThread());
}
}
}
class Thread2
{
public static void main(String args[])
{
y=new y();
x job1=new x(50,1000,n);
x job2=new x(80,0,n);
Thread t1=new Thread(job1,"job1");
Thread t2=new Thread(job2,"job2");
t1.start();
t2.start();
}
}
  
Stopping and Blocking a Thread:
Stopping Thread:
whenever we want to stop a thread from running further, we may do so by calling its stop() method, like
            Thread.stop();
The stop() may be used when the premature death of a thread is needed.

Blocking a Thread:
A thread can also be temporarly suspended or blocked from the runnable or running state by
            sleep()  // blocked for a specified time
            suspend()         //blocked until further orders
            wait()               //blocked until certain condition occurs
Again the thread enters into the running state from blocked state by resume() method in case of suspend() and the notify() method is called in the case of wait().

Life Cycle of a Thread:
Stages occured during the Life Cycle of a Thread
  1. Newborn State
  2. Runnable State
  3. Running State
  4. Blocked State
  5. Dead State
Newborn State:
When we create a thread object, the thread is born and is said to be in newborn state. At this state, we can do only one of the following things with it:
  • schedule it for running using start() method
  • kill it using stop() method
If scheduled it moves to the runnable state.

Runnable State:
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 the threads that are waiting for execution. If we want a thread to relinquish(give up) control to another thread of equal priority before it turn comes, we can do so by using the yield() method.

Running State:
 Running means that the processor has given its time to the thread for its execution. The thread runs until it gives up control on its own or it is preempted by a higher priority thread. A running thread may gives up  its control in one of the following situations.

1. It has been suspended using suspend () method. A suspended thread can be revived by using the resume() method.





2. It has been made to sleep. We can put a thread to sleep for a specified time period, where time is in milliseconds. This means that the thread is out of the queue during this time period. The thread re-enters the runnable state as soon as this time period is elapsed.



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


Blocked State:
 A thread is said to be blocked when it is prevented( not permitted) from 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.

Dead State:
 A running thread ends its life when it has completed executing its run() method. It is a natural death.  We can kill it by sending the stop() to it at any state thus causing a premature death to it.

Thread Class Methods:
Some commonly used methods of Thread Class are:

Method Name
Description
Static Thread currentThread()
Returns a reference to the currently executing thread object.
String getName()
Returns the name of the thread in which it is called.
int getPriority)
Returns the thread priority
Void interrupt()
Used for interrupting the thread
Void setName(String Newname)
Changes the name of the thread to new name
Void setPriority()
Changes the thread priority
Static void sleep(long millisec)
Causes the currently running thread to sleep
Void start()
Used to begin the execution of a thread. It calls the run()
Static void yield()
Used to pause temporarily to current thread object and allows other thread to execute
String toString()
Returns a string representation of thread. String includes threadgroup, threadsname and priority
Void destroy()
Destroys the thread without any cleanup.

Thread Exceptions:

Whenever we call a thread method that is likely to throw an exception, we have to supply an appropriate exception handler to catch it. The catch statement may take one of the following forms:

catch(ThreadDeath e)
{
//Killed Thread
 
            -----
            -----
}
catch(InterruptedException e)
{
            -----
            -----
}
catch(     )
{
            -----
            -----
}
catch(      )
{
            -----
            -----
}

Thread Priorities:

Java assigns to each thread a priority. Thread priority is an integer that specifies the relative priority of one thread to another. A thread can voluntarily relinquish its control. Threads relinquish control by explicitly yielding, sleeping, or blocking on pending Input/ Output operations. In this scenario, all other threads are examined, and the highest- priority thread that is ready to run gets the chance to use the CPU.

A higher-priority thread can pre-empt a low priority thread. In this case, a lower- priority thread that does not yield the processor is forcibly pre-empted. In cases where two threads with the same priority are competing for CPU cycles, the situation is handled differently by different operating systems.

Java thread class has defined two constants MIN_PRIORITY and MAX_PRIORITY. Any thread priority lies between MIN_PRIORITY and MAX_PRIORITY. Currently, the value of MIN_PRIORITY is 1 and MAX_PRIORITY is 10.

The priority of a thread is set at the time of creation. It is set to the same priority as the Thread that created it. The default priority of a thread can be changed by using the setPriority( ) method of Thread class.

Final void setPriority (int Priority_Level) where Priority_Level specifies the new priority for the calling thread.
To return a thread to default priority, specify Norm_Priority, which is currently 5.
You can obtain the current priority setting by calling the getPriority( ) method of thread class.
final int getPriority( ).

//program
class Thread_Priority
{
public static void main (String args [ ])
{
try
{
Thread Td1 = new Thread ("Thread1");
Thread Td2 = new Thread ("Thread2");
System.out.println ("Before any change in default priority:");
System.out.println("ThePriority of "+Td1.getName() +" is "+ Td1.getPriority());
System.out.println("The Priority of "+Td1.getName() +" is "+ Td2.getPriority());
//change in priority
Td1.setPriority(7);
Td2.setPriority(8);
System.out.println ("After changing in Priority:");
System.out.println("The Priority of "+Td1.getName() +" is "+ Td1.getPriority());
System.out.println("The Priority of "+Td1.getName() +" is "+ Td2.getPriority());
}
catch ( Exception e)
{
System.out.println("Main thread interrupted");
}
}
}
Output:
Before any change in default priority:
The Priority of Thread1 is 5
The Priority of Thread1 is 5
After changing in Priority:
The Priority of Thread1 is 7
The Priority of Thread1 is 8

Synchronization:

It is the process of running only one thread (or) one resource by making other threads to be wait in the queue. Synchronization is achieved with the help of an object called monitor which allows only one thread to enter by making other threads to wait. Once the thread in the monitor has completed the job either the next thread or thread based on higher priority will be executed. Synchronization is achieved in java with the help of a method called Synchronized() which can be applied either for methods (or) statements.

Ex:
While printing job has been assigned from different systems simultaneously, the task  should be done serially otherwise it may results to wrong prints. We make the  printing method synchronized such that the task will be done serially.

class SynchronizeDemo2
{
            public static void main(String args[])
            {
                        Shared shared = new Shared();
                        CustomThread thread1 = new CustomThread(shared, "one");
                        CustomThread thread2 = new CustomThread(shared, "two");
                        CustomThread thread3=new CustomThread(shared, "three");
                        CustomThread thread4 = new CustomThread(shared, "four");
                        try
                        {
                                    thread1.join();
                                    thread2.join();
                                    thread3.join();
                                    thread4.join();
                        }
                        catch(InterruptedException e) {}
            }
}

class CustomThread extends Thread
{
            Shared shared;
            public CustomThread(Shared shared, String string)
            {
                        super(string);
                        this.shared = shared;
                        start();
            }
            public void run()
            {
                        shared.doWork(Thread.currentThread().getName());
            }
}

class Shared
{
             synchronized void doWork(String string)
            {
                        System.out.println("Starting " + string);
                        try
                        {
                                    Thread.sleep(1000);
                        }
                        catch (InterruptedException e) { }
                        System.out.println("Ending " + string);
            }
}