Multithreading
Overview
Peter
Komisar © Conestoga
College version 5.7
/ 2010
Related Terms and Uses
Multiprogramming
Mainframes
were
designed
to allow several users to use
the computer at the
same time. Each user's process has
it's
own memory area or address space to hold
data and
instructions. The central processor does computations
for
short intervals on each user's program in sequence. This
provides the illusion that several things
are being done at
the same. This process is also called
'multiprogramming'.
The terms 'time
sharing', 'multitasking' and 'multithreading'
have also used.
Multitasking
Today
'multitasking'
is
normally used to describe the low-
level creation of
separate processes on an operating
system with the attendant
divisions of memory. An example
of multitasking the scenario where several DOS sessions
are run simultaneously on the same machine.
// multi-tasking - running several simultaneous
'heavyweight' DOS processes
The Platform
A
'platform' is often thought of as an operating system
used in
combination with a hardware system. For example
Linux running
on an Intel processor is a computer
platform.
When
a computer sets up a new process, there are a lot
of demands made
on system resources. As well, there is
a good deal of processing
involved in switching between
the
different 'contexts' associated with each of the processes
that
are running. For these reasons, mutltitasking is referred
to as a
'heavyweight' process. Multitasking
is also called
'timesharing' as each process will run in turn
for a few
milliseconds at a time.
// sometimes called timesharing
History
of Multithreading
Multithreading
is
now
reserved to describe the process
where many threads of
activity are created within a single
multitasking process. Multithreading is a newer phenomena
than
multitasking and came out of
experimentation that
went on in the seventies. A thread API
standard for POSIX,
(
the IEEE's Portable Operating System Interface
for
UNIX)
was described in 1995.
//
multithreading, several threads within a single process
//
more recent development, IEEE describe POSIX in 1995
In
the same year, 1995, Java was released with support
for
multi-threading built in. James Gosling gives credit for
the
ideas behind his Java thread model to the early
work
done by C.A.R. Hoare and also to the implementation of
threads that was provided in the
Cedar and Mesa languages
developed at Xerox PARC.
//
Multithreading uses the resources of a single process
// and has
little context switching costs
Because
in
multithreading
multiple activities are occurring
within a
process. The demand on system resources is that
of a single
process. There is little overhead associated with
context
switching within the program. Multithreading, then
is referred to
as a 'lightweight' process. When we
discuss
multithreading in Java we are talking about
creating many
lightweight threads of
activity within the same process
Multithreading Uses
One
of the key advantages to multithreading is it allows
several
things to occur in a user's program at
the same
time. For instance, a download that is managed in a
separate thread will not interfere with a
graphical user
interface's continued operation. Music
can be playing in
the background in another thread while the GUI
remains
responsive and the download
is going on.
// several independent events can occur concurrently
Parallel
Processing
Multithreading
threading
is
also useful to solve problems
that can better be
done by dividing the labor into parallel
processes. Consider a hypothetical phone directory that
has entries for all the people in North
America. An old
algorithm called 'divide and conquer'
involves testing if
a name is in the upper or lower half of the
book. Then
the process is repeated
on each subsection until the
name was found. The benefit of the
algorithm is that at
each turn the size of the list being checked
is halved.
If
the phone book is huge traversing the list might take
a while.
Another approach might be to divide the
book
into perhaps a hundred divisions and have each thread
divide and conquer or just 'brute
force' it's subsection.
//
parallel processes can subdivide a problem and work
// on sections
of it in tandem
Multithreading
Well Suited to some Application Designs
Another
use
for
multithreading is that some programs are
easier to write
and implement using threads. An example
of this is a server program. Having a server spawn a new
thread for each connection allows it to
deal with several
clients simultaneously. It should be
said that spawning too
many threads starts to have a negative impact as switching
contexts, even within a single process starts to take it's toll
on system
performance.
//
some applications are easier to create using multithreading
Java Threads
We
can give the first word on what Java threads are to the
inventor
of Java, James Gosling. His comments are
quoted
below.
"
Java's threads are pre-emptive, and depending on platform
on which
the Java interpreter
executes,
threads
can also be time-
sliced. On systems that don't
support time-slicing, once a thread
has started, the only way it will relinquish
control of the processor
is if
another thread of a higher priority takes control of the processor.
If your applications are
likely to be compute-intensive,
you might
consider how to give up control periodically
by using the yield( )
method
to give other threads a chance to run;
doing so will ensure
better interactive response
for graphical applications."
-
'The Java Language Environment'
-
James
Gosling
&
Henry McGilton
http://java.sun.com/docs/white/langenv/index.html
Don't Tie Up the AWT Thread
Event
handling
and
painting are handled by the AWT thread.
In short, if
something in an action method is going
to take a
long time, (a long calculation), spin off a new thread
to do it
to free up the event handling
ability of the AWT thread. Also
in this regard it is
recommended not to create new GUI
components
in new threads spun off from within action
methods as this will may lead to synchronization problems.
//
if a thread is 'spun' from an action method, creating a GUI
//
in this thread could create synchronization problems
Thread Scheduling
Preemptive
and Time-Sliced Scheduling
When
a Thread object's start( ) method is called a thread
of execution
begins. Calling start( ) registers the
thread
with the 'thread scheduler' making the thread eligible to
run on the 'Central Processing Unit' or
CPU. The thread
may then enter a competition with other threads
for CPU
time.
Thread
Mechanics
There are different
models which are used to schedule
thread activity. The two most
popularly implemented
models are 'preemptive' and 'time-sliced'.
Preemptive multithreading
assigns
each thread a priority and
threads with higher priority preempt
threads with lower priority
with access to the CPU. The
preemptive model affords some
predictability with respect to
which processes will be allowed
more access to the CPU.
'Time-sliced' scheduling
is also called
'round-robin' scheduling
and divides the time evenly between the
different threads that
have been started. Each thread has equal
time with the CPU.
Round-robin scheduling guards against one
thread monopolizing
the central processors time.
Don't
Count
on
Scheduling Behavior To Get
Predictable Results
Java
schedules preemptively, however this behavior
is
superimposed on the type of
scheduling that is incorporated
in the system that the JVM is
running on. On platforms that use
round robin scheduling, the
result may be a kind of hybrid of
preemptive and round-robin behavior.
// Java's model is superimposed on whatever model the operating system uses.
Because
the Java thread model needs is based on
the
underlying thread model of the operating system, behavior
may vary if a multithreaded application is
ported across
several platforms.
Accordingly
it
is not recommended that you lean heavily
on scheduling behavior
to derive any kind of strictly
predictable coding results.
Java Thread Priority Constants
Java
threads have priorities assigned to them. By default
priority is
set to an int value of 5. This value is
represented
by the constant, NORM_PRIORITY. MAX_PRIORITY
is
10, and MIN_PRIORITY
is 1. The Thread class has set
and get methods to set priority
or learn what the priority
is for a given
thread.
Example
t1.setPriority( t1.getPriority( ) +1 );
// increments a thread's priority by one
ThreadGroup Class
Threads
can
be
grouped into sets so they can be called
on a single method
invocation. Thread grouping provides
a
mechanism to coordinate thread activity. A thread group
can
also include other thread groups forming a tree where
every
thread group except the initial thread
group has a
parent. A thread can access information about its own
thread group, but not it's thread group's
parent thread
group or any other thread groups.
The class has a version
of interrupt( ) to stop all the threads
in a group at once.
Example
ThreadGroup tg = Thread.currentThread( ).getTheadGroup( );
The following
example demonstrate demonstrates how
ThreadGroup's interrupt( )
method can be used to stop
a group of threads. For now ignore other
features of the
thread which we are very close to explaining later
in the
note.
ThreadGroup Example
public
class TGroup{
static int count;
public static void
main(String[]args){
ThreadGroup tg1 =new
ThreadGroup("GroupOne");
Team t1 = new
Team(tg1,"Chicago");
Team t2 = new Team(tg1,"New
York");
Team t3 = new Team(tg1,"Boston");
ThreadGroup
tg2 =new ThreadGroup("GroupTwo");
Team t4 = new
Team(tg2,"Montreal");
Team t5 = new
Team(tg2,"Toronto");
Team t6 = new
Team(tg2,"Detroit");
t1.start( );
t2.start( );
t3.start( );
t4.start( );
t5.start( );
t6.start( );
}
}
class
Team extends Thread{
ThreadGroup tg;
String name;
Team(ThreadGroup
tg,String name){
super(tg,name);
this.name=name;
this.tg = tg;
}
// what a thread does is in it's
run( ) method
// here it counts and sleeps until the limit is
reached
public void
run( ){
try
{
while(true)
{
System.out.println(name);
TGroup.count = TGroup.count + 1;
System.out.println("Game Count: " +
TGroup.count);
Thread.sleep((long)( Math.random( ) * 5000 + 1));
if (TGroup.count>20){
tg.interrupt( );
}
}
}
catch(InterruptedException ie)
{
System.out.println(name + ": Our group has been
interrupted!");
}
}
}
How many Thread?
Each
thread has a default stack size of 400K. Peter Van
der Linden in
his text 'Just Java' reported using a
32-bit
Unix machine with 2GB user address space was able
to
create 2000 'do nothing' threads on the
machine before
it quit.
// coexisting threads taking up CPU time and memory space
Thread States
The
Running State // in
control
Threads exist in a
number of states during their life cycle.
First there is the
'running state'. This is the condition where
a thread has control
of the central processing unit. Then
there are a variety of 'wait
states'. A number of thread
methods cause a thread to go into the
wait state. In this
state the thread is not seeking the attention
of the CPU.
// certain Thread methods put threads into wait( ) states
Wait
State Methods
Certain of Thread class
methods put a thread into this state
and include wait( ), sleep(
) and yield( ). (The suspend( )
method has been deprecated so we
don't count it. ) Notice
wait( ) is not a method defined in
the Thread class and
instead is one of the core methods that all
classes inherit
from Object.
// wait states ---> ready state ---> running ---> dead
The
Blocked Condition
The 'blocked' condition
is not caused by a method call.
Instead, it is a behavior that
saves on CPU cycles. As an
example, the read( ) methods of the IO classes go
into a
blocked state if there is nothing available to read.
Thread
States
Running |
the thread has control of the CPU |
Wait |
caused by wait( ),
sleep( ), yield( ) or |
Ready |
not waiting for anything except the CPU |
Dead |
the run( ) method has returned |
The
Dead State
The
final state is the 'dead' state. When
run( ) returns
the thread is said to be 'dead'. Dead threads are
unusual
conceptually. Though they are no
longer eligible to run
again, their methods can still be called.
The
dead state implies the object is no longer involved in
scheduling behavior however is still resident in
memory
as a callable object. In a sense, a thread in a dead state,
becomes or should we say remains, a regular Java
object.
A
Baseball Analogy
(If you don't mind a
baseball analogy, running is like
being 'up to bat', ready is 'on
deck' and wait states are
like being
on the bench. In the preemptive model, the
coach frequently uses
pinch hitters putting them ahead
of other players. High
priority players get to bat regardless
of how long others have
waited.
Round-robin
scheduling is like the coach that is
fair,
(perhaps to a fault) . Every player goes in turn regardless
if it will result in the loss of the
game.
A
dead thread is like a player that finishes his turn
at bat
for the last time in the game though he remains in the dug-
out, still technically an active player in the game until the
game is finished.
The
Deprecated stop( ) Method
It
use to be that to kill a thread the stop( ) method was
called.
A lot of early texts showed many
examples of
the stop( ) method being called on a thread.
Unfortunately
there are serious
problems with the stop( ) method and
a few of it's associates
so they are now deprecated.
The
Java documentation describes emphatically what
deprecations have
occurred. The
following table excepts
from an early API the explanation why stop( ),
and the
suspend and resume( ) methods were deprecated.
Major
Thread Method Deprecations void stop( ) -deprecated - inherently
unsafe. Stopping a thread void suspend( ) -deprecated. as it is inherently deadlock-prone. resume(
)
-deprecated. -exists solely for
use
with suspend( ), See 'Why are
Thread.stop,
Thread.suspend and Thread. |
A
common recommendation to
decommission a thread
is to first call interrupt(
) on it then set it's reference to null.
Example
some_thread.interrupt(
);
some_thread = null;
This
approach alone doesn't work that well, as the
thread will resume it's activity if not put completely out
of commission somehow.
Alternatives
To the stop( ) Method
The
recommended interrupt( ) and null combo can be
'ignored' by a
stubborn thread and will often need some
help from a control
statement.
A
way to enforce the interrupt is to use a System.exit( )
in the
catch clause. If you don't want to leave the program
but just a
loop, a 'break' to a label can be used. These
various techniques
are commented out in the following
example. Comment them in one
at a time to see them
work.
First
there
is
the deprecated stop( ) method. In the catch
clause
there is a System.exit( ), a 'break' statement and
a 'return'
statement that all do the job without the danger
of a 'deadlock'
that may occur using the stop( ) method.
Stopping A Thread Sample Code
class
_7Up{
public static void main(String args[]){
Up up =
new Up();
up.start();
try{
Thread.sleep(5000);
}
catch(InterruptedException ie)
{
System.out.println("Outer IOException");
}
up.interrupt();
up = null;
// up.stop( );
// works well but is
now 'taboo'' ..........................
1.
}
}
class Up extends Thread{
int i;
public
void run( ){
while(true){
System.out.println(i);
i++;
try{
Thread.sleep(1000);}
catch(InterruptedException ie)
{
System.out.println("Time's up for
Up");
//
System.exit(0); // one way
out! .................................
2.
// break ; // another way
out,(could be used with a label) 3.
//
return; // return also works to end
run .....................
4.
}
}
}
}
Using a Variable Flag to End a Loop & Stop a Thread
It
is not the best programming practice to use error controls
to
control program flow, though this design is used in
many
real-time applications. We might consider the above code
an
example of the how to use the interrupt( ) method.
A
better design is
to let Thread's run( ) methods complete
and exit naturally. If
a
thread
has a loop that needs to be
terminated
a
boolean variable can act as a flag to signal
the thread to
terminate.
This represents a
'natural death' as the thread is
terminated
by the return of the run( ) method.
This approach is shown in the following example.
Flagging
a Loop Variable in a String
class
Summer implements Runnable
{
boolean flag=true;
public void
run( )
{
while(flag==true)
{
System.out.println("Rain");
try{Thread.sleep(1000);}
catch(InterruptedException
ie){}
}
}
}
class Winter implements Runnable
{
boolean flag=true;
public void
run()
{
while(flag==true)
{
System.out.println("Snow");
try{Thread.sleep(1000);}
catch(InterruptedException
ie){}
}
}
}
class Seasons{
public static void main(String[]args){
Summer summer = new Summer();
Winter winter = new Winter();
Thread thummer = new Thread(summer);
Thread thinter = new Thread(winter);
thummer.start();
thinter.start();
//
lets it rain and snow for 10 seconds
try{
Thread.sleep(5000);
}
catch(InterruptedException
ie){}
summer.flag=false;
winter.flag=false;
System.out.println("A nice exit!");
}
}
Thread Mechanics
Java's Design Was Based on a Thread Model
Java
was designed on a foundation that provides support
for threads.
In fact, Java runs in a threaded environment.
For instance, Java
depends on a background thread called
the 'gc' thread or 'garbage collector' to automatically free
or
'deallocate' memory that is no longer being used. Java
also
assigns the management of painting graphical
components and
handling the events they generate to a
separate thread called the 'Event thread' (aka the AWT
thread
).
The Thread Class
Java
supplies these lightweight processes called 'threads'
via
instances of the Thread class. The
Thread class
supplies a set of methods to manage the life cycle
of
any threads the developer
creates. In Java a thread is
an instance of the Thread class.
Thread is one of the
fundamental language classes in the
java.lang package
and does not require any
explicit package imports.
// Java threads are instances of the java.lang.Thread class
A
Java Thread object can be thought of as a Virtual Central
Processing
unit or Virtual CPU. In this analogy the
thread's
start( ) method serves to turn the CPU on. The run( )
method
is supplies to the thread
process what main does for a stand-
alone Java program. The
run( ) method supplies the point of
entry for the activities that
will be executed by the thread.
Any
number of such threads of activity can be created within
the
practical limits of the system's memory
and performance
characteristics.
Comparing
a Thread to a Java Virtual Machine running a main( ) Application
Virtual Machine |
Thread |
central processing unit |
Thread object // dynamic part |
power on // call 'java' on program |
start( ) method |
main( ) method |
run( ) method |
Details
of Thread Activity in the Java Virtual
Machine
Each
Java application runs in a single instance of the
Runtime class.
Runtime defines methods like exec( )
and exit( ). The exit( ) method initiates a shutdown
sequence for the current runtime object.
Typically, the
exit( ) method is called from the System class, as
in
the following.
Example
System.exit(0);
// zero indicates a normal exit
The
0 int value is a status code are used to
indicate a
normal exit. Non-zero status codes indicate
abnormal
halts.
For
interests sake, the following Runtime class demo
shows the getRuntime( ) method invoked, exec( ) used
to start an copy of notepad and a call on freeMemory( )
to check memory. Other exec( ) methods allow fancier
command executions.
Runtime Class Demo
import
java.io.*;
class RuntimeInfo{
public static void main(String[] args){
try
{
Runtime rt= Runtime.getRuntime();
rt.exec("notepad");
System.out.println("You should see notepad running if on
Windows");
System.out.println("Free Memory: " + rt.freeMemory());
}
catch(IOException io)
{
System.out.println(io );
}
}
}
A Single Non-daemon Thread Calls main( )
Aside
from
the
background threads such as the Garbage
Collector and the
Event thread the Java Virtual Machine
starts a single, non-daemon thread that calls the
main( )
method of the class that has been supplied as a parameter
to the 'java' runtime command.
This
thread and any others that are started will run until
one of
two conditions occur. Either the exit( ) method
is
called in the runtime environment, (and
the security manager
has permitted the exit to happen), or all
the non-daemon
threads have died.
The non-daemon threads will have
died either by having their
run( ) methods return or by
throwing an
exception that propagates beyond the name
scope
of the run( ) method.
Conditions
that Stop the Runtime Thread
The exit( ) method is called
all non-daemon threads run( ) methods return
an exception propagates beyond a thread's run( ) method's scope
Thread
Support
Most
thread support resides in class Thread. There is a
special kind
of support that allows thread activity
to be
coordinated and communicating that resides in the
Object
class. There is also some additional help supplied by the
Runtime Environment.
Thread Exception
Progogation
Exception
propagation
in
a thread instance is limited to
the
thread so a problem in one thread
will not to interfere
with the activities of other processes.
Thread class has
the following declaration.
Thread Class Signature
public
class
Thread
extends Object implements Runnable
//
Thread implements Runnable
The Runnable Interface
The
Runnable interface defines the single method run( )
as shown in
the interface declaration below. When
run( )
is overridden, it must be
declared public, returning void
and taking no arguments.
It is inside the run( ) method
that the work that is being given
to the thread is contained.
The
Runnable Interface
public
interface
Runnable
{
public void run( );
}
Two Approaches To Creating Threads
There
are two basic approaches to creating threads.
You
can either extend Thread class and
thereby inherit
the Runnable behavior or you can implement
Runnable
in a class that becomes a target
for a Thread constructor.
These
two
variations
can be
summarized as follows.
Two Basic Approaches to Creating Threads
1)
Subclass Thread and override run( )
2)
Target an object that implements Runnable
Subclass
Thread // an advantage and a work-around
Extending
Thread
has
the advantage of making it's
methods readily available
for use in the subclass.
This
isn't so when implementing Runnable. There is
though
a work-around. A reference to the currently executing
thread can be obtained via the static
call on the method
currentThread( ) from inside run( ). Then
Thread class
methods can be called
using this reference.
Example
Thread current = Thread.currentThread( )
Extending
Thread is not always possible because of
Java's single
inheritance model. For
instance, applets
extend Applet class therefore cannot also
extend Thread.
An applet's
only choice is to implement Runnable.
A summary of the steps involved are as follows:
Subclassing Thread Approach
1)
extend Thread
2) override run( ) in
the subclass
3) create an instance
of the subclass and call start( ) on
it.
// start calls run( )
Subclassing Thread Sample Code
class
BlueBird extends Thread{
public
void run( ){
System.out.println("BlueBird ");
}
}
class
Birder{
public
static void main(String[]args){
BlueBird blue = new BlueBird( );
blue.start( );
}
}
Target a Runnable Object
The second approach
involves creating a class that
implements the Runnable interface.
This class is
instantiated and supplied as an argument to a
Thread
class constructor. This is summarized in the following
steps.
Summary of Approach Targeting a Runnable Object
1)
Create a class which implements Runnable
2)
Provide an instance of Runnable to a Thread constructor
3)
Instantiate and call start( ) on the instance
For
this approach, the thread constructor with the following
form is
used. The Runnable target instance
provides the
implementation of the method.
Example
public Thread(Runnable target)
Code
where a Runnable Object is Targeted by a Thread Constructor
class
TargetClass implements Runnable{
public void run( ){
System.out.println
("Thread takes target and starts it's run");
}
}
class
TargetRun{
public static void
main(String[]args){
TargetClass target = new TargetClass( );
Thread arrow = new Thread(target);
arrow.start( );
}
}
In
both cases the run( ) method is overridden and
the start( )
method is called on the Thread object.
Key Thread Class Methods
The
sleep( ) Method
We
used the sleep( ) method above. The sleep( ) method
is a static
method, which causes the currently executing
string to
'time-out' for a time specified in
milliseconds, or
milliseconds and nanoseconds
Time is accurate only in
the respect that the thread won't
re-enter until that time
elapses. It goes into the ready state in
which condition
there is no
guarantee when it will run again.
// guarantees to sleep( ) the given time, not when it runs
The
sleep( ) method throws InterruptedException. As long
as the exception is not thrown the method guarantees a
minimum
amount of sleep time. The sleep( )
method is
very useful in a number of applications, for instance
to
introduce periodicity into visual animations.
Sample Code showing sleep( ) being used
class
Counter
extends
Thread{
//
Press Control-C to end
public void
run(){
int count=0;
while(true){
count=count+1;
System.out.println(count);
try{
Thread.sleep(1000);
}catch(InterruptedException ie){ }
}
}
}
class
Count{
public static void main(String[]
args){
Counter
count=new
Counter();
count.start();
}
}
The
yield( ) Method
yield(
)
is
a static method which moves the executing
thread to ready
state where it waits or re-executes.
Calling yield( ) at regular intervals ensures a single
process
doesn't monopolize the CPU, permitting other
threads to execute. To ensure the thread
is checked
occasionally, the time-consuming thread is set to a
priority that is lower than the thread that needs to be
checked
occasionally and yield( ) is called periodically
to let the occasional thread to run.
//
set time consuming thread to lower priority than thread
//
that takes little time
The
following code ( in green )shows yield( ) being
used.
Each class that runs in it's own thread shows a different
character pattern on screen.
On
Linux, when both threads
yield( ) within their loops they
share the CPU evenly. Without
yields the output is a bit of
a 'free-for-all' where there is
erratic sharing.
Using
sleep(
) with the sleep times of each
thread using
different ratios seems to allow reasonably
predictable
control over how much time each thread would have
at the
CPU.
Try
the following on Windows and compare the behaviour
to that of Linux.
yield(
) Code Example
//
use Ctrl_C to stop process
class
Lots extends Thread{
public void run(){
while(true){
System.out.print("|||||");
//
Using sleeps with different ratios of sleep times
//
seems like a better way to get proportional runtime
//
behavior
//
try{Thread.sleep(300);}catch(InterruptedException ie){ }
//
commenting in yields in one thread or the other
// causes
one thread to predominate but still allowing
// the other to
run
// when both threads yield there is shared
behavior
//
Thread.yield( );
}
}
}
class
Little extends Thread{
public void run(){
while(true){
System.out.print("-----");
//
try{Thread.sleep(100);}catch(InterruptedException ie){ }
//
Thread.yield( );
}
}
}
class
LotsLittle{
public static void
main(String[] args){
Lots
lots=new Lots();
Little
little=new Little();
//
lots.setPriority(5);
//
little.setPriority(5);
// setting priorities did not
have a discernible
// effect on Linux
on 8086 architecture
lots.start( );
little.start( );
}
}
OUTPUTS
// Linux on 8086
a ) Code
as is, an erratic mix of all one character or the other
--------------------------------------------------------- |
b)
Uncommenting yield( ) methods yields nice shared
behavior,
at least on Linux on 8086.
-----|||||-----|||||-----|||||-----|||||-----|||||-----|||||-----||||| |
c
) Using sleep( ) with different ratios of sleep time
was effective
in controlling proportionately how long
one thread would run
relative to the other.
||||||||||-----||||||||||-----||||||||||-----||||||||||-----||||||||||-----|||||||||| |
d
) Setting priorities had little discernible
effect on this
machine.
The
interrupt( ) Method
To
causes a thread to abandon a process such as an
I/O operation
interrupt( ) can be called. Calling
interrupt( )
causes an InterruptedException to be thrown. You can
catch this exception to implement a
'time-out' in a
process. For example,
Example
catch(InterruptedException
ie)
{
break;
}
The interrupt( )
method was demonstrated in the code
sample shown earlier called
_7UP.
The join( ) Method
The
join( ) method provides a way to allow one thread
to stop what it
is doing until another thread is
completely
finished it's activity. This method provides a
rudimentary
form of communication between
threads as one thread
is allowed to
complete before the next thread is started.
In
the following example, two threads are
created that
both more or less take turns accessing the CPU. By
uncommenting the join( ) method, one
of the threads
'politely' waits until it's associate thread
has completely
finished.
Code
demonstrating the use of join( )
class Blue
extends Thread
{
Blue(String s)
{
super(s);
}
public void run()
{
int count=0;
for(int i=0;i<10;i++)
{
count=count+1;
System.out.println(getName() + " " +
count);
try
{
Thread.sleep(300);
}
catch(InterruptedException ie)
{
}
} // for
}
// run
}
// class
class Red extends Thread
{
Red(String s)
{
super(s);
}
public void run( )
{
int count=0;
for(int i=0;i<10;i++)
{
count=count+1;
System.out.println(getName() + " " +
count);
try
{
Thread.sleep(300);
}
catch(InterruptedException ie)
{
}
} //
for
}
// run
} //
class
// try different combinations of join
class RedBlue
{
public static void main(String[] args)
{
Red red=new Red("Red Thread");
Blue blue=new Blue("Blue Thread");
// start with
try catch block and join commented out
//
try{
red.start( );
//
red.join(
);
blue.start( );
// don't
need to join( ) blue as red is not re-contending
//
}
//
catch(InterruptedException ie){/*report*/}
} // main
} // class
Blocking
Blocking
is
not
a method, but a behavior. when forced
to wait on some
external factor, the thread steps out of
the running state and is said to be blocked. For instance,
when a method has to wait to read from a
socket, the
method will 'try' to read a byte
immediately. If none is
available, rather
than tying up the running state, the method
'steps
out' of the way and is said to be blocked (All Java
IO methods
are designed to behave this way).
The setDaemon( ) Method
The
setDaemon( ) method makes a thread a 'daemon'
versus a 'user'
thread. In Java a daemon thread is a
service provider whose value is predicated on a user
thread
being present. The JVM can only exit if zero
user threads are
running.
If
you want a thread to run but
not prevent a user from
exiting the JVM, making the thread a
daemon thread
will accomplish this. Making a
service a daemon thread
takes care of
freeing the resources associated with the
thread should the main
server terminate.
Example
thisService.setDaemon(true);
daemon
//
around Kitchener-Waterloo often pronounced day-mon
Pronounced "demon." A UNIX program that
executes in the // also pronounced like 'diamond' as in Raphael |
Deprecated methods suspend( ), resume( ) & stop( )
Just
for completeness we re-confirm the deprecation of
the suspend( ),
resume( ) and stop( ). In
the case of the
suspend( ) method a thread receiving a suspend
call stays
suspended until it
receives a resume( ) call. A thread can
be suspended by
itself or another thread but only resumed
by
another thread. A suspended thread can
easily become
permanently suspended as it cannot reactivate
itself. A
resume( ) call on a thread
that is not suspended is simply
ignored. The deprecation of the
stop( ) method makes the
interrupt(
) method more important then before.
The
Thread class has many interesting constructors
and
methods. It is worth taking a
few minutes to visit the class
in the JDK documentation.
Self Test Multithreading Basics Self Test With Answers
1) Which of the
following terms is used almost exclusively to describe
processes with processes?
a) multiprogramming
b) time sharing
c)
multitasking
d) multithreading
2) Regarding
preemptive multithreading which of the following statements is least
correct?
a) threads with higher priority preempt threads with
lower priority
b) the preemptive model affords some
predictability with respect to which
processes
will be run
c) Java's preemptive model
is unaffected by the underlying system's
thread model.
d) If all threads are given equal priority values
they will behave more or less like
a
time-sliced system.
3) Which of the
following is least correct in describe the different states threads
can assume?
a) Running
b) Blocked
c) Ready
d)
Dead
4) Which of the
following variations that result in the creation of wait states is a
method but is not defined in the Thread class.
a) yield( )
b) wait( )
c) block
d) sleep( )
5)
In comparing an thread instance of a Java multithreaded environment
to a virtual
computer system,
calling the start( ) method can be thought of as corresponding to
which of the following?
a)
a Virtual Machine
b) main( ) method
c) Power On
d)
a CPU
6) Consider the two
approaches to obtaining Thread behavior. When the
Runnable
interface is implemented which of the following is not correct?
a) The Thread class
constructor targets the Runnable object.
b) Both the Thread
object and Runnable object are instantiated.
c) The Runnable
object will supply a definition for the run( ) method.
d) The
start( ) method is called on the Runnable object.
Exercise
Please be
careful to note and answer all the questions!
1) Create seven
Thread classes each a Thread extension
named after each day of the
week. Have each print to screen
what day they are from inside
Runnable's run( ) method.
Instantiate each in another class that
has a main( ) method.
Call on a reference for each the start( )
method. Run the main
class and briefly describe what you observe
with respect to
order.
2) Because each class
will execute so quickly their order
will dictate largely when they
will execute. Add the following
lines to the run( ) method ahead
of the System.out.println( )
statement so they have an more even
chance in the 'race'.
public void run(
){
try{Thread.sleep((int)(Math.random()*50+1));}
catch(InterruptedException ie){ie.toString();}
//
etc
2) Apply thread
priorities to attempt to attempt to have the days
print in the
correct order. Run the prioritized threads several
times. In
Linux the method had little or no effect. What do
you observe on
Windows XP?
Example
lots.setPriority(5);
3) Comment out the
priority setting methods. In the main
method( ), immediately
following each thread's start( ) call,
call the join( ) method on
the thread's reference.
Example
monday.start( ) ;
monday.join( );
What effect did the join method have on the output?
4)
Create Runnable interfaces for the 4 seasons where
each Runnable
will print to screen the name of the season
associated with the
object.
Use the second technique
discussed for creating thread
objects where the Runnable object
is supplied to a Thread
constructor to create 4 threads
representing the seasons
that print the Season names to screen.
4) Modify the
constructor used to include names. Use the
getName() method to output these names to screen.