Executing the tasks is of two types:
· Single Tasking: Executing only one task
at a time is called single tasking. In this single tasking the microprocessor
will be sitting idle for most of the time. This means micro processor time is
wasted.
· Multi tasking: Executing more than one
task at a time is called multi tasking.
Multitasking is of two types:
o
Process Based Multitasking: Executing several
programs simultaneously is called process based multi tasking.
o
Thread Based Multitasking: Executing different
parts of the same program simultaneously with the help of a thread is called
thread based multitasking.
Advantage of multitasking is
utilizing the processor time in an optimum way.
Java provides built-in support for multithreaded
programming. A multithreaded program
contains two or more parts that can run concurrently. Each part of such a
program is called a thread. Thread is a smallest unit of code. Thread is also
defined as a subprocess. A Thread sometimes called an execution context or a
light weight process.
Uses of Threads:
· Threads
are used in designing serverside programs to handle multiple clients at a time.
· Threads
are used in games and animations.
Program 1: Write
a program to know the currently running Thread
//Currently running thread
class Current
{
public static void main(String
args[])
{
System.out.println ("This is
first statement");
Thread
t = Thread.currentThread ();
System.out.println
("Current Thread: " + t);
System.out.println
("Its name: " + t.getName ());
System.out.println
("Its priority:" + t.getPriority ());
}
}
Output:
· Write a class that extends Thread class
or implements Runnable interface this is available in lang package.
· Write public void run () method in that
class. This is the method by default executed by any thread.
· Create
an object to that class.
· Create
a thread and attach it to the object.
· Start
running the threads.
Program 2: Write
a program to create and run a Thread.
//creating and running a Thread
class MyThread extends Thread
{ public void
run ()
{ for
(int i = 0;i<100;i++)
{
System.out.print
(i + "\t");
}
}
}
class TDemo
{ public
static void main(String args[])
{
MyThread obj = new MyThread
(); Thread
t = new Thread (obj);
t.start
();
}
}
Output:
Multi Tasking Using Threads: In multi tasking, several tasks are executed at a time. For this purpose, we need more than one thread. For example, to perform 2 tasks we can take 2 threads and attach them to the 2 tasks. Then those tasks are simultaneously executed by the two threads. Using more than one thread is called ‘multi threading’.
Program 3: Write a program to create
more than one thread. //using more than one thread is called Multi Threading
class Theatre extends Thread
{ String str;
Theatre (String str)
{ this.str
= str;
}
public void run()
{ for
(int i = 1; i <= 10 ; i++)
{
System.out.println (str + "
: " + i);
try
{
Thread.sleep (2000);
}
catch
(InterruptedException ie) { ie.printStackTrace (); }
}
}
}
class TDemo1
{ public
static void main(String args[])
{ Theatre
obj1 = new Theatre ("Cut Ticket");
Theatre
obj2 = new Theatre ("Show Chair");
Thread
t1 = new Thread (obj1);
Thread
t2 = new Thread (obj2);
t1.start
(); t2.start
();
}
}
Output:
In the preceding example, we have used 2 threads on the 2 objects of TDemo1 class. First we have taken a String variable str in Theatre class. Then we passed two strings- cut ticket and show chair into that variable from TDemo1 class. When t1. start () is executed, it starts execution run () method code showing cut ticket. Note that in run () method, we used: Thread. sleep (2000) is a static method in Thread class, which is used to suspend execution of a thread for some specified milliseconds. Since this method can throw InterruptedException, we caught it in catch block. When Thread t1 is suspended immediately t2. start () will make the thread t2 to execute and when it encounters Thread.sleep(2000), it will suspend for specified time meanwhile t1 will get executed respectively. In this manner, both the threads are simultaneously executed.
Multiple Threads
Acting on Single Object: When two people (threads) want to perform same
task then they need same object (run () method) to be executed each time. Take
the case of railway reservation. Every day several people want reservation of a
berth for them. The procedure to reserve the berth is same for all the people.
So we need some object with same run () method to be executed repeatedly for
all the people (threads).
Let us think
that only one berth is available in a train and two passengers (threads) are
asking for that berth in two different counters. The clerks at different
counters sent a request to the server to allot that berth to their passengers.
Let us see now to whom that berth is allotted. Program 4: Write a program to create multiple threads and make the
threads to act on single object.
//Multiple Threads acting on
single object class Reserve implements Runnable
{
int available = 1;
int wanted;
Reserve (int i)
{ wanted
= i;
}
public void run()
{ synchronized
(this)
{
System.out.println ("Number
of berths available: " + available);
if
( available >= wanted)
{
String name =
Thread.currentThread ().getName (); System.out.println
(wanted + " berths alloted to: " + name);
try
{
Thread.sleep (2000); // wait for
priniting the ticket
available
= available - wanted;
}
catch
(InterruptedException ie)
{
ie.printStackTrace (); }
}
else
{
System.out.println
("Sorry, no berths available");
}
}
}
}
class Safe
{ public
static void main(String args[])
{ Reserve
obj = new Reserve (1);
Thread
t1 =new Thread (obj); Thread
t2 = new Thread (obj);
t1.setName
("First Person");
t2.setName ("Second
Person");
t1.start
(); t2.start
();
}
}
In the preceding example, we have used 2 threads on the 2 objects of TDemo1 class. First we have taken a String variable str in Theatre class. Then we passed two strings- cut ticket and show chair into that variable from TDemo1 class. When t1. start () is executed, it starts execution run () method code showing cut ticket. Note that in run () method, we used: Thread. sleep (2000) is a static method in Thread class, which is used to suspend execution of a thread for some specified milliseconds. Since this method can throw InterruptedException, we caught it in catch block. When Thread t1 is suspended immediately t2. start () will make the thread t2 to execute and when it encounters Thread.sleep(2000), it will suspend for specified time meanwhile t1 will get executed respectively. In this manner, both the threads are simultaneously executed.
Multiple Threads
Acting on Single Object: When two people (threads) want to perform same
task then they need same object (run () method) to be executed each time. Take
the case of railway reservation. Every day several people want reservation of a
berth for them. The procedure to reserve the berth is same for all the people.
So we need some object with same run () method to be executed repeatedly for
all the people (threads).
Let us think
that only one berth is available in a train and two passengers (threads) are
asking for that berth in two different counters. The clerks at different
counters sent a request to the server to allot that berth to their passengers.
Let us see now to whom that berth is allotted.
Program 4: Write a program to create multiple threads and make the threads to act on single object.
Program 4: Write a program to create multiple threads and make the threads to act on single object.
//Multiple Threads acting on
single object class Reserve implements Runnable
{
int available = 1;
int wanted;
int available = 1;
int wanted;
Reserve (int i)
{ wanted
= i;
}
public void run()
{ synchronized
(this)
{
System.out.println ("Number
of berths available: " + available);
if
( available >= wanted)
{
String name =
Thread.currentThread ().getName (); System.out.println
(wanted + " berths alloted to: " + name); try
{
Thread.sleep (2000); // wait for
priniting the ticket
available
= available - wanted;
}
catch
(InterruptedException ie)
{
ie.printStackTrace (); }
}
else
{
System.out.println
("Sorry, no berths available");
}
}
}
}
class Safe
{ public
static void main(String args[])
{ Reserve
obj = new Reserve (1);
Thread
t1 =new Thread (obj); Thread
t2 = new Thread (obj); t1.setName
("First Person"); t2.setName ("Second
Person");
t1.start
(); t2.start
();
}
}
Output:
If we would not use synchronized (this) block in the preceding program then when thread t1 enter into the run () method, it sees available number of berths as 1 and hence it allots it to First Person and displays “1 Berths reserved for First Person”. Then it enters try { } block inside run () method, where it will sleep for 2 seconds. In this time, the ticket will be printed on the printer. When the first thread is sleeping thread t2 also enters the run () method, it also sees that there is 1 berth remaining. The reason is for this is that the available number of berths is not yet updated by the first thread. So the second thread also sees 1 berth as available and it allots the same berth to the Second Person. Then the thread t2 will also go into sleep state. Thread t1 wakes up first and then it updates the available number of berths to zero (0). But at the same time the second thread has already allotted the same berth to the Second Person also. Since both the threads are acting on the same object simultaneously, the result will be unreliable.
Thread
Synchronization or Thread Safe: When a thread is acting on an object
preventing other threads from acting on the same object is called Thread
Synchronization or Thread Safe. The Object on which the Threads are
synchronized is called synchronized object or Mutex (Mutually Exclusive Lock).
Thread synchronization is done in two ways:
· Using
synchronized block we can synchronize a block of statements.
e.g.: synchronized (obj)
{
statements;
}
· To synchronize an entire method code we
can use synchronized word before method name e.g.: synchronized void method ()
{
}
ThreadCreation: To create a Thread, we can use the following forms:
ThreadCreation: To create a Thread, we can use the following forms:
Thread
t1 = new Thread ();
Thread
t2 = new Thread (obj);
Thread
t3 = new Thread (obj, "thread-name");
Thread Class Methods:
· To
know the currently running thread: Thread
t = Thread.currentThread ();
· To
start a thread: t.start
();
· To
stop execution of a thread for a specific time:
Thread.sleep (milliseconds);
· To
get the name of the thread: String
name = t.getName ();
· To
set the new name to the thread: t.setName
("New Name");
· To
get the priority of the thread: int
priority = t.getPriority();
· To
set the priority of the thread: t.setPriority
(int priority);
Thread priorities can change from 1 to 10. We can also use
the following constants to represent priorities: Thread.MAX_PRIORITY value is 10
Thread.MIN_PRIORITY value is 1
Thread.NORM_PRIORITY value is 5
· To
test if a thread is still alive: t.isAlive
() returns true/false
· To
wait till a thread dies: t.join
();
· To
send a notification to a waiting thread: obj.notify
();
· To
send notification to all waiting threads: obj.notifyAll
();
· To
wait till the obj is released (till notification is sent): obj.wait ();
Deadlock: When a
Thread locked an object and waiting for another object to be released by
another Thread, and the other thread is also waiting for the first thread to
release the first object, both the threads will continue waiting forever. This
is called "Thread Deadlock".
Even if we
synchronize the threads, there is possibility of other problems like deadlock.
Daily, thousands of people book tickets in trains and cancel tickets also. If a
programmer is to develop code for this, he may visualize that booking tickets
and canceling them are reverse procedures. Hence, he will write these 2 tasks
as separate and opposite tasks and assign 2 different threads to do these tasks
simultaneously.
To book a
ticket, the thread will enter the train object to verify that the ticket is
available or not. When there is a ticket, it updates the available number of
tickets in the train object. For this, it takes say 150 milli seconds. Then it
enters the compartment object. In compartment object, it should allot the
ticket for the passenger and update its status to reserved. This means the
thread should go through both the train and compartment objects.
Similarly, let us think if a thread has to cancel a ticket,
it will first enter compartment object and updates the status of the ticket as
available. For this it is taking say 200 milliseconds. Then it enters train
object and updates the available number of tickets there. So, this thread
alsoshould fo through both the compartment and train objects.
When the
BookTicket thread is at train object for 150 milliseconds, the CancelTicket
thread will be at compartment object for 200 milliseconds. Because we are using
multiple (more than one) threads, we should synchronize them. So, the threads
will lock those objects. When 150 milliseconds time is over, BookTicket thread
tries to come out of train object and wants to lock on compartment object, by
entering it. At that time, it will find that the compartment object is already
locked by another thread (CancelTicket) and hence it will wait. BookTicket
thread will wait for compartment object for another 50 milli seconds.
After 200
milliseconds time is up, the CancelTicket thread which is in compartment object
completes its execution and wants to eneter and lock on train object. But it
will find that the train object is already under lock by BookTicket thread and
hence is not available. Now, CancelTicket will wait for the train object which
should be unlocked by BookTicket.
In this way, BookTicket thread keeps on waiting for the
CancelTicket thread to unlock the compartment object and the CancelTicket
thread keeps on waiting for the BookTicket to unlock the train object. Both the
threads will wait forever in this way, this situation is called DealLock.
//to cancel the ticket
class CancelTicket extends Thread
{ Object
train, comp;
CancelTicket (Object train, Object
comp)
{ this.train
= train;
this.comp
= comp;
}
public void run()
{
synchronized
(comp)
{
System.out.println ("Cancel
ticket has locked on compartment");
try
{
Thread.sleep
(2000);
}
catch
(InterruptedException ie) {
}
System.out.println
("Cancel ticket tries to lock train object...");
synchronized
(train)
{
System.out.println
("Cancel ticket has locked train...");
}
}
}
}
//to book the ticket
class BookTicket extends Thread
{ Object
train, comp;
BookTicket (Object train, Object
comp)
{ this.train
= train;
this.comp
= comp;
}
public void run()
{ synchronized
(train)
{
System.out.println
("Book ticket has locked on train");
try
{
Thread.sleep
(2000);
}
catch
(InterruptedException ie)
{
}
System.out.println
("Book ticket tries to lock train object...");
synchronized
(comp)
{
System.out.println
("Book ticket has locked compartment...");
}
}
}
} class Dead
{ public
static void main (String args[])
{ Object
train = new Object ();
Object
compartment = new Object ();
CancelTicket
obj1 = new CancelTicket (train, compartment);
BookTicket
obj2 = new BookTicket (train, compartment);
Thread
t1 = new Thread (obj1);
Thread
t2 = new Thread (obj2);
t1.start
(); t2.start
();
}
}
Output:
There is no
specific solutioin for preventing deadlock. The programmer should exercise
proper caution while planning the logic of the program to avoid deadlocks.
Thread Communication:
In some cases two or more threads should communicate with each other. One
thread output may be send as input to other thread. For example, a consumer
thread is waiting for a Producer to produce the data (or some goods). When the
Producer thread completes production of data, then the Consumer thread should
take that data and use it.
In producer class we take a StringBuffer object to store
data, in this case; we take some numbers from 1 to 5. These numbers are added
to StringBuffer object. Until producer completes placing the data into
StringBuffer the consumer has to wait. Producer sends a notification
immediately after the data production is over.
Program 6: Write
a program to demonstrate Thread communication
//inter thread communication
class Producer implements Runnable
{ StringBuffer
sb;
Producer ()
{
sb = new StringBuffer();
}
public
void run () { synchronized
(sb)
{
for (int i=1;i<=5;i++)
{
try
{
sb.append (i + " : ");
Thread.sleep
(500);
System.out.println (i + " appended");
}
catch (InterruptedException
ie){}
}
sb.notify
();
}
}
}
class Consumer implements Runnable
{ Producer
prod;
Consumer (Producer prod)
{
this.prod = prod;
}
public
void run()
{ synchronized
(prod.sb)
{
try
{
prod.sb.wait
();
}
catch (Exception e) { }
System.out.println
(prod.sb);
}
}
}
class Communicate
{ public
static void main(String args[])
{
Producer obj1 = new Producer ();
Consumer
obj2 = new Consumer (obj1);
Thread
t1 = new Thread (obj1);
Thread
t2 = new Thread (obj2);
t2.start
(); t1.start
();
}
}
Output:
Both sleep () and wait () methods are used to suspend a
thread execution for a specified time. When sleep () is executed inside a
synchronized block, the object is still under lock.When wait () method is
executed, it breaks the synchronized block, so that the object lock is removed
and it is available.
Thread Group: A
ThreadGroup represents a group of threads. The main advantage of taking several
threads as a group is that by using a single method, we will be able to control
all the threads in the group.
· Creating
a thread group: ThreadGroup tg
= new ThreadGroup (“groupname”); · To
add a thread to this group (tg):
Thread t1 = new Thread (tg, targetobj, “threadname”);
· To
add another thread group to this group (tg):
ThreadGroup tg1 = new
ThreadGroup (tg, “groupname”);
· To
know the parent of a thread:
tg.getParent ();
· To
know the parent thread group:
t.getThreadGroup (); This returns a ThreadGroup object to which the
thread t belongs.
· To
know the number of threads actively running in a thread group: t.activeCount ();
· To
change the maximum priority of a thread group tg: tg.setMaxPriority
();
Program 7: Write
a program to demonstrate the creation of thread group.
//Using ThreadGroup import
java.io.*;
class WhyTGroups
{ public
static void main (String args[]) throws IOException
{ Reservation
res = new Reservation ();
Cancellation
can = new Cancellation ();
//Create
a ThreadGroup
ThreadGroup
tg = new ThreadGroup ("Reservation Group");
//Create
2 threads and add them to thread group
Thread
t1 = new Thread (tg, res, "First Thread");
Thread
t2 = new Thread (tg, res, "Second Thread");
//Create
another thread group as a child to tg
ThreadGroup
tg1 = new ThreadGroup (tg, "Cancellation Group");
Thread
t3 = new Thread (tg1, can, "Third Thread");
Thread
t4 = new Thread (tg1, can, "Fourth Thread");
//find
parent group of tg1
System.out.println
("Parent of tg1 = " + tg1.getParent ());
//set maximum priority tg1.setMaxPriority (7);
System.out.println
("Thread group of t1 = " + t1.getThreadGroup ());
System.out.println
("Thread group of t3 = " + t3.getThreadGroup ()); t1.start
(); t2.start
(); t3.start
(); t4.start
();
System.out.println
("Number of threads in this group : " + tg.activeCount () );
}
}
class Reservation extends Thread
{ public void
run ()
{ System.out.println
("I am Reservation Thread");
}
}
class Cancellation extends Thread
{ public void
run ()
{ System.out.println
("I am Cancellation Thread");
}
}
Output:
Thread States (Life-Cycle of a Thread): The life cycle of a thread contains several states. At any time the thread falls into any one of the states.
The thread that was just
created is in the born state.
· The
thread remains in this state until the threads start method is called. This
causes the thread to enter the ready state.
· The highest priority ready thread enters
the running state when system assigns a processor to the thread i.e., the
thread begins executing.
· When a running thread calls wait the
thread enters into a waiting state for the particular object on which wait was
called. Every thread in the waiting state for a given object becomes ready on a
call to notify all by another thread associated with that object.
· When a sleep method is called in a
running thread that thread enters into the suspended (sleep) state. A sleeping
thread becomes ready after the designated sleep time expires. A sleeping thread
cannot use a processor even if one is available.
· A thread enters the dead state when its
run () method completes (or) terminates for any reason. A dead thread is
eventually be disposed of by the system.
· One common way for a running thread to
enter the blocked state is when the thread issues an input or output request.
In this case a blocked thread becomes ready when the input or output waits for
completes. A blocked thread can’t use a processor even if one is available.