You are on page 1of 43

Multiple threads

A process is a self-contained running program with its own


address space.
A thread is a single sequential flow of control within a process.

A single process can have multiple concurrently executing


threads.
The Thread Class and the Runnable Interface

Runnable defines a single, general-purpose method:


public interface Runnable
{
abstract public void run();
}
Every thread begins its life by executing a run() method in a
particular object.
A new thread is born when we create an instance of the
java.lang.Thread class.
The constructor for the Thread class accepts information
about where the thread should begin its execution.
Creating and starting threads
A newly born Thread remains idle until we call its start() method.

The thread then wakes up and proceeds to execute the run()


method of its target object.

start() can be called only once in the lifetime of a Thread.

Once a thread starts, it continues running until the target object's


run() method completes, or we call the thread's stop() method to
kill the thread permanently.
class Animation implements Runnable
{ ...
public void run()
{ while ( true )
{……
}
}
}
To use it:
Animation happy = new Animation("Mr. Happy");
Thread myThread = new Thread( happy );
myThread.start();
... Here we have created an instance of our Animation class and passed it
as the argument to the constructor for myThread.
We can have our Animation class perform these actions in its
constructor:
class Animation implements Runnable
{ Thread myThread;
Animation (String name)
{ myThread = new Thread( this );
myThread.start();
} ...
Class Animation implements Runnable

creates
myThread = new Thread() Thread myThread
myThread.start(); start();
run{ }
The Thread class itself implements the Runnable interface;
it has its own run() method we can override to make it do something
useful:
class Animation extends Thread {
... public void run() class Thread implements Runnable
{ ……
}
}
class Animation extends Thread
Animation bouncy = new
Animation("Bouncy"); start( )

bouncy.start(); run{ }
A Thread's Life
A Thread continues to execute until one of the following things happens:
•It returns from its target run() method
•It's interrupted by an uncaught exception
•Its stop() method is called
So what happens if the run() method for a thread never terminates,
and the application that started the thread never calls its stop() method?
The answer is that the thread lives on, even after the application that
created it has finished.
In many cases, what we really want is to create background threads
that do simple, periodic tasks in an application.
The setDaemon() method can be used to mark a Thread as a daemon
thread that should be killed and discarded when no other application
threads remain.
Normally, the Java interpreter continues to run until all threads have
completed.
But when daemon threads are the only threads still alive, the
interpreter will exit.
class CountThread extends Thread{
main
int from ,to;
public CountThread(int f,int t){ 0..9 10..19 20..29
from = f; to = t;
}
public void run(){
for(int i=from;i<to;i++)
System.out.println("i = " + i);
}
public static void main(String args[]){
for(int i=0;i<3;i++) {
CountThread t = new CountThread (i*10,(i+1)*10);
t.start();
} } }
Thread States
• When a Thread is first created, it is in the NEW State
• When you invoke start method, the thread changes to
RUNNABLE state ( eligible for execution )
• When certain events happen to a RUNNABLE thread, it may
enter the NOT RUNNABLE state. When a thread is NOT
RUNNABLE, it is still alive, but it is not eligible for
execution.
• A NOT RUNNABLE thread becomes RUNNABLE again
when the condition that caused the thread to become NOT
RUNNABLE ends
• When a thread terminates, it is said to be DEAD
Thread States

NEW

start( )
resume( )/ notify( ) / sleep
timeout IO Finished NOT RUNNABLE
RUNNABLE /BLOCKED
suspend( )/ wait()/
sleep() / IO BLOCKED

run( ) ends
stop( ) DEAD
Thread – Control Methods
start() Used to start the execution the thread
stop() Deprecated. Used to stop the execution of the
thread no matter what the thread is doing
suspend() Deprecated. Used to temporarily stop the
execution of the thread.
resume() Deprecated. Used to resume the execution of a
suspended thread.
sleep(long millisec) A class method that causes the Java
Runtime to put the Caller thread to sleep. The
InterruptedException, may be thrown.
join() Used for the caller’s thread to wait for this thread to
die.
yield( ) It is used to make sure other threads have the
chance to run.
Thread Information
currentThread( ) Return’s the Caller Thread

getName ( ) Return’s the current name of the Thread

getThreadGroup( ) Return’s the parent thread group of Thread

getPriority( ) Return’s the current priority of the Thread

isAlive( ) Return’s true if the Thread is started but not dead yet.

isDaemon( ) Return’s true if Thread is a daemon thread.


Thread Group Information
getName( ) Return’s the name of the Group
getParent( ) Return’s the parent Thread Group
getMaxPriority ( ) Return’s the max priority of the Group
activeCount( ) Return’s the no of active Thread’s in the
Group
activeGroupCount( ) Return’s the no active thread group’s
enumerate(Thread list[ ] , boolean recursive)
Adds all the active threads in this thread group into
the list array. If recursive all the threads in the
subthread groupswill be copied over as well.
Returns number of threads copied.
ThreadGroup Tree

system

Reference MAIN
gc
Handler
main MyGroup

T1 T2 T3
public class TInfo{
public static void main(String args[ ]){
ThreadGroup root,parent; root=
Thread.currentThread( ).getThreadGroup(); root.list();
parent = root.getParent(); parent.list();
} }
java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]
java.lang.ThreadGroup[name=system,maxpri=10]
Thread[Reference Handler,10,system]
Thread[Finalizer,8,system]
Thread[Signal Dispatcher,10,system]
java.lang.ThreadGroup[name=main,maxpri=10]
Thread[main,5,main]
Examples
class WithoutThread{
public static void main(String args[]){
NoThread p = new NoThread();
p.run(); show("Another task starts");
}
static long basetime = System.currentTimeMillis();
static void show(String msg)
{
long elapsedtime = System.currentTimeMillis()- basetime;
System.out.println(msg + " at " + (elapsedtime/1000.0) + "
seconds");
}
}
class NoThread // not a thread
{ NoThread()
{ WithoutThread.show("Nothread created");
}
public void run()
{ WithoutThread.show("Nothread started");
try{
Thread.sleep(10000);
}
catch(InterruptedException e){ }
WithoutThread.show("Nothread finishes");
}
}
Modify it to Thread
class WithThread
{ public static void main(String args[])
{ Threaded p = new Threaded();
p.start();
show("Another task starts");
}
static long basetime = System.currentTimeMillis();
static void show(String msg)
{
long elapsedtime = System.currentTimeMillis()- basetime;
System.out.println(msg + " at " + (elapsedtime/1000.0) + " seconds");
}}
class Threaded extends Thread
{ Threaded()
{
WithThread.show("Nothread created");
}
public void run()
{ WithThread.show("Nothread started");
try{ Thread.sleep(10000);
}
catch(InterruptedException e){}
WithThread.show("Nothread finishes");
}}
Thread Methods
public class JoinTest {
public static void main(String args[]) {
FirstThread first = new FirstThread();
SecondThread second = new SecondThread(); first.start();

second.start(); try
{ first.join();
second.join();
}catch(InterruptedException e) { }
System.out.println("Main thread will end..");
}
}
class FirstThread extends Thread {
public void run(){
try{ System.out.println("First thread starts running..");
sleep(1000);
System.out.println("First thread finishes running..");
}catch(InterruptedException e){}
}}
class SecondThread extends Thread {
public void run(){
try{ System.out.println("Second thread starts running..");
sleep(2000);
System.out.println("Second thread finishes running..");
}catch(InterruptedException e){}} }
setDaemon( true)
class FirstThread extends Thread
{
FirstThread () { setDaemon(true); }
…….

class SecondThread extends Thread


{
SecondThread () { setDaemon(true); }
……
Main thread will end..
First thread starts running..
Second thread starts running..
import java.awt.*; import java.util.*;
import java.text.DateFormat;
import java.applet.Applet;
/*<applet code =clock width =100 height=100></applet>*/
public class clock extends Applet implements Runnable
{ Thread clockThread = null;
public void start()
{ if(clockThread == null)
{ clockThread = new Thread(this,"Clock");
clockThread.start();
}
}
public void run() { while(clockThread != null)
{ repaint();
try { Thread.sleep(1000);
}
catch(InterruptedException e) {}
} }
public void paint(Graphics g)
{ Calendar cal = Calendar.getInstance();
Date date = cal.getTime();
DateFormat dF = DateFormat.getTimeInstance();
g.drawString(dF.format(date),5,10);
}
public void stop(){ clockThread = null; } }
Animation Example
Thread Synchronization
All Objects and classes are associated with a monitor.
The monitor ensures that only one thread has access to the
resource at any given point in time.
A Synchronized method acquires the monitor of an object when it
is invoked for that object.
During the execution of a synchronized method, the object is
locked so that no other synchronized method can be invoked.
The monitor is automatically released as soon as the method
completes its execution.

The monitor may be released when the synchronized method


executes certain methods like wait ( ) method.
Monitor
Method 1
Threads in Queue

Method 2

Method 3
Examples on Synchronization
INTER THREAD COMMUNICATION
If data is produced by one thread and consumed by another
thread. The consumer has to check every now and then whether it
has to data to act upon.
This is a huge waste of CPU time.

If the producer would communicate to consumer once it has


finished producing the required data. The consumer need not use
up CPU cycles just to check whether the producer has done its
job.
This communication between threads is called Inter-Thread
communication.
Inter Thread Communication Methods
wait
public final void wait() throws InterruptedException
The thread releases ownership of this monitor and waits
until another thread notifies threads waiting on this object's
monitor to wake up either through a call to the notify method or
the notifyAll method. The thread then waits until it can re-
obtain ownership of the monitor and resumes execution.
This method should only be called by a thread that is the
owner of this object's monitor.
notify
public final void notify()
Wakes up a single thread that is waiting on this object's monitor. If
any threads are waiting on this object, one of them is chosen to be
awakened.
notifyAll
public final void notifyAll()
Wakes up all threads that are waiting on this object's monitor.
yield
public static void yield()
Causes the currently executing thread object to temporarily
pause and allow other threads to execute.
Interaction between two threads: a Producer and a Consumer.
A producer thread creates messages and places them into
a queue, while a consumer reads them out and displays
them.
We have our consumer thread be lazy and run much
slower than the producer.
This means that Producer occasionally has to stop and wait
for Consumer to catch up.
The Consumer example shows the Producer and Consumer
classes.
Our Producer runs faster than our Consumer.
Producer would like to generate a new message every second,
while Consumer gets around to reading and displaying a
message only every three seconds.
import java.util.Vector;
class Producer extends Thread {
static final int MAXQUEUE = 5;
private Vector messages = new Vector();
public void run() {
try {
while ( true ) {
putMessage();
sleep( 1000 );
}
}
catch( InterruptedException e ) { } }
private synchronized void putMessage() throws
InterruptedException {
while ( messages.size() == MAXQUEUE ) wait();
messages.addElement( new java.util.Date().toString() );
notify();
}
// Called by Consumer
public synchronized String getMessage() throws
InterruptedException { notify();
while ( messages.size() == 0 ) wait();
String message = (String)messages.firstElement();
messages.removeElement( message );
return message; } }
class Consumer extends Thread {
Producer producer;
Consumer(Producer p) { producer = p; }
public void run() {
try { while ( true ) {
String message = producer.getMessage();
System.out.println("Got message: " +
message);
sleep( 3000 );
}
} catch( InterruptedException e ) { }
}
public static void main(String args[]) {
Producer producer = new Producer();
producer.start();
new Consumer( producer ).start();
}
}
Most of the necessary changes are in the Consumer class; the
example below shows the code for the modified class.
class Consumer extends Thread {
Producer producer;
String name; Consumer(String
name, Producer producer) { this.producer =
producer; this.name = name; }
public void run()
{
try {
while ( true ) {
String message = producer.getMessage();
System.out.println(name + " got message: " + message);
sleep( 2000 ); }
} catch( InterruptedException e ) { }
}
public static void main(String args[]) {
Producer producer = new Producer();
producer.start(); //
Start two this time new
Consumer( "One", producer ).start(); new
Consumer( "Two", producer ).start(); } }

The only modification to make in the Producer code is to change the call
to notify() in putMessage() to a call to notifyAll().
Here is some sample output when there are two consumers running, as
in the main() method shown above:
One got message: Wed Mar 20 20:00:01 CST 1996
Two got message: Wed Mar 20 20:00:02 CST 1996
One got message: Wed Mar 20 20:00:03 CST 1996
Two got message: Wed Mar 20 20:00:04 CST 1996
……
Reentrant locks are important because they eliminate the
possibility of a single thread's deadlocking itself on a lock that it
already holds.
Consider this class:
public class Reentrant {
public synchronized void a() {
b();
System.out.println("here I am, in a()");
}
public synchronized void b()
{ System.out.println("here I am, in b()");
}
}
Reentrant contains two synchronized methods: a and b.
The first, a, calls the other, b. When control enters method a, the
current thread acquires the lock for the Reentrant object.
Now a calls b; because b is also synchronized, the thread
attempts to acquire the same lock again.
Because the Java platform supports reentrant locks, this works.
In platforms that don't support reentrant locks, this sequence of
method calls causes deadlock.
The current thread can acquire the Reentrant object's lock again,
and both a and b execute to conclusion, as is evidenced by the
output:
here I am, in b()
here I am, in a()

You might also like