Multithreaded Programming
Multithreaded Programming
printing.
The Thread Class and Runnable Interface
• Java’s multithreading system is built upon the Thread class and its
companion interface, Runnable.
• To create a new thread, your program will either extend Thread or
implement the Runnable interface.
• The Thread class defines several methods that help manage
threads.
GRNICA 3
The Main Thread
• When a Java program starts up, one thread begins running
immediately. This is usually called the main thread of our
program.
• The main thread is important for two reasons :
• It is the thread from which other “child” threads will be
spawned.
• Often, it must be the last thread to finish execution because it
performs various shutdown actions.
• Main thread can be controlled through a Thread object.
• To do so, we must obtain a reference to it by calling the method
currentThread(), a public static member of Thread.
GRNICA 4
class CurrentThreadDemo {
public static void main(String args[]) {
Changes the name of
Thread t = Thread.currentThread();
the thread from main
System.out.println("Current thread: " + t); to “My Thread”
t.setName("My Thread");
System.out.println("After name change: " + t);
try { 1.sleep method to pause.
for(int n = 5; n > 0; n--) { 2. The argument
System.out.println(n); specifies the delay in
Thread.sleep(1000); milliseconds.
} 3. It might throw an
} catch (InterruptedException e) { interrupted exception.
System.out.println("Main thread interrupted");
}
}
} GRNICA 5
The name of the thread, its
priority and the name of its
group.
Implementing Runnable
• The easiest way to create a thread is to create a class that
implements the Runnable interface.
•We can construct a thread on any object that implements the
Runnable interface. Runnable defines only one method called
run( ).
NewThread()
{
t = new Thread(this, "Demo Thread"); // Create a new, second thread
System.out.println("Child thread: " +Starts
t); the execution of thread
t.start(); beginning at the run()
} method.
GRNICA 9
// This is the entry point for the second thread.
public void run()
{
try
{
for(int i = 5; i > 0; i--)
{
System.out.println("Child Thread: " + i);
Thread.sleep(500);
}
}catch (InterruptedException e)
{
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
} GRNICA 10
class ThreadDemo {
public static void main(String args[])
{
new NewThread(); // create a new thread
try
{
for(int i = 5; i > 0; i--)
{
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e)
{
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
GRNICA 11
}
Extending Thread
• The second way to create a thread is to create a new class that
extends Thread, and then to create an instance of that class.
• The extending class must override the run() method, which is the
entry point for the new thread.
• It must also call start() to begin the execution of new thread.
NewThread(String threadname)
{
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
t.start(); // Start the thread
}
GRNICA 15
public void run()
{
try
{
for(int i = 5; i > 0; i--)
{
System.out.println(name + ": " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e)
{
System.out.println(name + "Interrupted");
}
System.out.println(name + " exiting.");
}
}
GRNICA 16
class MultiThreadDemo
{
public static void main(String args[])
{
new NewThread("One"); // start threads
new NewThread("Two");
new NewThread("Three");
try
{
Thread.sleep(10000);
} catch (InterruptedException e)
{
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");
}
} GRNICA 17
Using isAlive() and join()
GRNICA 21
try {
mt1.t.join();
mt2.t.join();
mt3.t.join();
}
catch(InterruptedException exc)
{
System.out.println("Main thread interrupted.");
}
System.out.println("Child one is alive:" +mt1.t.isAlive());
System.out.println("Child two is alive:" +mt2.t.isAlive());
System.out.println("Child three is alive:" +mt3.t.isAlive());
System.out.println("Main thread ending.");
}
}
GRNICA 22
Thread Priorities
• Each thread has associated with it a priority setting. A thread’s
priority determines, in part, how much CPU time a thread receives.
• In general, low-priority threads receive little. High priority threads
receive a lot.
• It is important to understand that factors other than a thread’s
priority also affect how much CPU time a thread receives.
• When a child thread is started, its priority setting is equal to that of
its parent thread.
• You can change a thread’s priority by calling setPriority( ), which
is a member of Thread. This is its general form:
final void setPriority(int level)
GRNICA 23
• Here, level specifies the new priority setting for the calling thread.
• The value of level must be within the range MIN_PRIORITY and
MAX_PRIORITY.
• Currently, these values are 1 and 10, respectively. To return a thread
to default priority, specify NORM_PRIORITY, which is
currently 5.
• These priorities are defined as final variables within Thread.
• You can obtain the current priority setting by calling the
getPriority( ) method of Thread, shown here:
GRNICA 24
class clicker implements Runnable
{
int click = 0;
Thread t;
private volatile boolean running = true;
public clicker(int p)
{ It is used to ensure that
t = new Thread(this); the value of running is
t.setPriority(p); examined each time the
} following loop iterates.
GRNICA 25
public void run()
{
while (running)
{
click++;
}
}
public void stop()
{
running = false;
}
public void start()
{
t.start();
}
} GRNICA 26
class HiLoPri
{
public static void main(String args[])
{
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
clicker hi = new clicker(Thread.MIN_PRIORITY + 3);
clicker lo = new clicker(Thread.MIN_PRIORITY + 1);
lo.start();
hi.start();
try
{
Thread.sleep(5000);
} catch (InterruptedException e)
{
System.out.println("Main thread interrupted.");
}
GRNICA 27
lo.stop();
hi.stop();
GRNICA 30
Using Synchronized Methods
• Synchronization is easy in Java, because all objects have their own
implicit monitor associated with them.
• To exit the monitor and relinquish control of the object to the next
waiting thread, the owner of the monitor simply returns from the
synchronized method.
GRNICA 31
// this program is not synchronized
class Callme
{
void call(String msg)
{
System.out.print("[" + msg);
try
{
Thread.sleep(3000);
} catch (InterruptedException e)
{
System.out.println("Interrupted");
}
System.out.println("]");
}
}
GRNICA 32
class Caller implements Runnable
{
String msg;
Callme target;
Thread t;
public Caller(Callme targ, String s)
{
target = targ;
msg = s;
t = new Thread(this);
t.start();
}
public void run()
{
target.call(msg);
}
} GRNICA 33
class Synch{
public static void main(String args[])
{
Callme target = new Callme();
Caller ob1 = new Caller(target, "Hello");
Caller ob2 = new Caller(target, "Synchronized");
Caller ob3 = new Caller(target, "World");
// wait for threads to end
try
{
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch(InterruptedException e) {
System.out.println("Interrupted");
}
} GRNICA 34
}
The synchronized Statement
• Although creating synchronized methods within classes that we
create is an easy and effective means of achieving synchronization,
it will not work in all cases.
• For ex. You want to use a class that does not use synchronized
methods & this class is not created by you.
• Thus, it is not possible for you to add synchronized to the
appropriate methods within the class.
• How can access to an object of this class be synchronized?
• The solution is easy: You simply put calls to the methods defined
by this class inside a synchronized block.
GRNICA 35
• This is the general form of a synchronized block:
synchronized ( object )
{
// statements to be synchronized
}
• Here, object is a reference to the object being synchronized.
• A synchronized block ensures that a call to a method that is a
member of object will take place only after the object’s monitor has
been entered by the calling thread.
GRNICA 36
// Uses synchronized block.
class Callme
{
void call(String msg)
{
System.out.print("[" + msg);
try
{
Thread.sleep(3000);
} catch (InterruptedException e)
{
System.out.println("Interrupted");
}
System.out.println("]");
}
}
GRNICA 37
class Caller implements Runnable
{
String msg;
Callme target;
Thread t;
public Caller(Callme targ, String s)
{
target = targ;
msg = s;
t = new Thread(this);
t.start();
}
public void run() { // synchronize calls to call()
synchronized (target) { // synchronized block
target.call(msg);
}
} GRNICA 38
}
class Synch1{
public static void main(String args[])
{
Callme target = new Callme();
Caller ob1 = new Caller(target, "Hello");
Caller ob2 = new Caller(target, "Synchronized");
Caller ob3 = new Caller(target, "World");
// wait for threads to end
try
{
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch(InterruptedException e) {
System.out.println("Interrupted");
}
} GRNICA 39
}
Interthread Communication
• Consider the following situation. A thread called T is executing
inside a synchronized method and needs access to a resource
called R that is temporarily unavailable.
• What should T do? If T enters some form of polling loop that waits
for R, T ties up the object, preventing other threads’ access to it &
wastes the CPU time.
• A better solution is to have T temporarily relinquish control of the
object, allowing another thread to run. When R becomes available,
T can be notified and resume execution.
• Such an approach relies upon some form of interthread
communication in which one thread can notify another that it is
blocked, and be notified that it can resume execution.
GRNICA 40
• Java supports interthread communication with the wait( ), notify( ),
and notifyAll( ) methods.
• wait() tells the calling thread to give up the monitor and go to
sleep until some other thread enters the same monitor & calls
notify().
• notify() wakes up a thread that called wait() on the same object.
• notifyAll() wakes up all the threads that called wait() on the
same object. One of the threads will be granted access.
GRNICA 42
// An incorrect implementation of a producer and consumer.
class Q {
int n;
GRNICA 43
class Producer implements Runnable {
Q q;
Producer(Q q) {
this.q = q;
new Thread(this, "Producer").start();
}
while(true) {
q.put(i++);
}
}
}
GRNICA 44
class Consumer implements Runnable {
Q q;
Consumer(Q q) {
this.q = q;
new Thread(this, "Consumer").start();
}
GRNICA 45
class PC {
public static void main(String args[]) {
Q q = new Q();
new Producer(q);
new Consumer(q);
GRNICA 46
//A correct implementation of a producer and consumer.
class Q
{
int n;
boolean valueSet = false;
synchronized int get()
{
while(!valueSet)
try
{
wait();
} catch(InterruptedException e) {}
System.out.println("Got: " + n);
valueSet = false;
notify();
return n;
} GRNICA 47
synchronized void put(int n)
{
while(valueSet)
try
{
wait();
} catch(InterruptedException e) {}
this.n = n;
valueSet = true;
System.out.println("Put: " + n);
notify();
}
}
GRNICA 48
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++);
}
}
} GRNICA 49
class Consumer implements Runnable
{
Q q;
Consumer(Q q)
{
this.q = q;
new Thread(this, "Consumer").start();
}
public void run()
{
while(true)
{
q.get();
}
}
}
GRNICA 50
class PCFixed
{
public static void main(String args[])
{
Q q = new Q();
new Producer(q);
new Consumer(q);
System.out.println("Press Control-C to stop.");
}
}
GRNICA 51
Deaklock
• A special type of error that you need to avoid that relates
specifically to multitasking is deadlock, which occurs when two
threads have a circular dependency on a pair of synchronized objects.
• Deadlock is a difficult error to debug for two reasons:
• In general, it occurs only rarely, when the two threads time-
slice
in just the right way.
• It may involve more than two and two synchronized objects.
GRNICA 52
class A
{
synchronized void foo(B b)
{
String name = Thread.currentThread().getName();
System.out.println(name + " entered A.foo");
try
{
Thread.sleep(1000);
} catch(Exception e) {}
System.out.println(name + " trying to call B.last()");
b.last();
}
synchronized void last()
{
System.out.println("Inside A.last");
}
GRNICA 53
}
class B
{
synchronized void bar(A a)
{
String name = Thread.currentThread().getName();
System.out.println(name + " entered B.bar");
try
{
Thread.sleep(1000);
} catch(Exception e) {}
System.out.println(name + " trying to call A.last()");
a.last();
}
synchronized void last()
{
System.out.println("Inside A.last");
} GRNICA 54
}
class Deadlock implements Runnable
{
A a = new A();
B b = new B();
Deadlock()
{
Thread.currentThread().setName("MainThread");
Thread t = new Thread(this, "RacingThread");
t.start();
GRNICA 55
public void run()
{
b.bar(a); // get lock on b in other thread.
System.out.println("Back in other thread");
}
GRNICA 56
Suspending, Resuming, and Stopping Threads
Using Java 1.1 and Earlier
GRNICA 57
class NewThread implements Runnable
{
String name; // name of thread
Thread t;
NewThread(String threadname)
{
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
t.start(); // Start the thread
}
GRNICA 58
// This is the entry point for thread.
public void run()
{
try
{
for(int i = 15; i > 0; i--)
{
System.out.println(name + ": " + i);
Thread.sleep(200);
}
} catch (InterruptedException e) {}
System.out.println(name + " exiting.");
}
}
GRNICA 59
class SuspendResume
{
public static void main(String args[]) {
NewThread ob1 = new NewThread("One");
NewThread ob2 = new NewThread("Two");
try {
Thread.sleep(1000);
ob1.t.suspend();
System.out.println("Suspending thread One");
Thread.sleep(1000);
ob1.t.resume();
System.out.println("Resuming thread One");
ob2.t.suspend();
System.out.println("Suspending thread Two");
Thread.sleep(1000);
ob2.t.resume();
System.out.println("Resuming
GRNICA
thread Two"); 60
} catch (InterruptedException e) {}
// wait for threads to finish
try
{
System.out.println("Waiting for threads to finish.");
ob1.t.join();
ob2.t.join();
} catch (InterruptedException e) {}
System.out.println("Main thread exiting.");
}
}
GRNICA 61
Suspending, Resuming, and Stopping Threads
Using Java 2
• The suspend( ) method of the Thread class is deprecated in Java
2. This was done because suspend( ) can sometimes cause serious
system failures.
• The resume( ) method is also deprecated. It does not cause
problems, but cannot be used without the suspend( ) method as its
counterpart.
• The stop( ) method of the Thread class, too, is deprecated in Java
2. This was done because this method can sometimes cause serious
system failures.
GRNICA 63
// Suspending and resuming a thread for Java 2
class NewThread implements Runnable
{
String name; // name of thread
Thread t;
boolean suspendFlag;
NewThread(String threadname)
{
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
suspendFlag = false;
t.start(); // Start the thread
}
GRNICA 64
// This is the entry point for thread.
public void run() {
try {
for(int i = 15; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(200);
synchronized(this) {
while(suspendFlag) {
wait();
}
}
}
} catch (InterruptedException e) {
System.out.println(name + " interrupted.");
}
System.out.println(name + " exiting.");
} GRNICA 65
void mysuspend(){
suspendFlag = true;}
synchronized void myresume() {
suspendFlag = false;
notify();
}
}
class SuspendResume {
public static void main(String args[]) {
NewThread ob1 = new NewThread("One");
NewThread ob2 = new NewThread("Two");
try {
Thread.sleep(1000);
ob1.mysuspend();
System.out.println("Suspending thread One");
Thread.sleep(1000);
ob1.myresume();
GRNICA 66