Multithreading                       Peter Komisar


Multiprogramming

Mainframes were designed to allow several users to use the computer at the same
time. Each user's process would have it's own memory area or address space to
hold data and instructions. The central processor would then do computations a bit
at a time on each user's program in sequence. This provided the illusion that several
things were being done at the same. The old name for this was 'multiprogramming'
though the terms time sharing, multitasking and multithreading were also used.

Multitasking

Today multitasking is used to describe the low-level creation of separate processes
with their attendant divisions of memory. An example of this is running several DOS
sessions simultaneously. Multitasking is defined at the system level. The system is
comprised of the combination of operating system and the hardware platform that
the OS is running on. For example, a platform might be a version of Linux running
on an Intel processor. Because there are a lot of the systems resources involved in
setting up new processes, and there is a lot of work that needs to be done to switch
between the context of each process, mutltitasking is referred to as a heavyweight
process. Multitasking is also called timesharing as each process would run in turn for
a couple milliseconds.
 

Multithreading

Multithreading is now reserved to describe creating many threads of activity within
a single multitasking process. Multithreading is a newer phenomena than multitasking
and came out of experimentation that was going on in the mid-seventies. A thread API
standard was described in 1995 for POSIX, ( the IEEE's Portable Operating System
Interface for UNIX). The same year Java was released with multithreading support
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.

Because in multithreading the multiple activities are occurring within a process, not
as many extra resources need to be allocated so multithreading is also referred to as
a lightweight activity. 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 not interfere in a graphical user interface continued operation.
Music can be playing in the background in another thread while the GUI remains
responsive and the download is going on.

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 problem with
our book is traversing the list might take a long time. Another approach might be to
divide the book into perhaps a hundred divisions and have each thread divide and
conquer it's subsection. (The optimal number of thread would need to be determined
as starting too many threads can start to slow the system down.

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 again spawning too many threads may not be good as it can take a toll on the
system's performance.
 
  The Java Language Environment   James Gosling & Henry McGilton 
   http://java.sun.com/docs/white/langenv/index.html

 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. 
.

Preemptive and Time-Sliced Scheduling

When a Thread object's start( ) method is called thread execution begins. Calling
start( ) registers the thread with the thread scheduler making the thread eligible to
run on the CPU. The thread may then enter a competition with other threads for
CPU time.

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 so each has equal time with the cpu.
Round-robin scheduling guards against one thread monopolizing the central processors time.

Java schedules preemptively, however this behaviour is superimposed on the type of
scheduling that is incorporated in the system that the JVM is running on. Some Windows
platforms use round robin scheduling, so the result is a hybrid of preemptive and round-
robin behaviour. Behaviour may vary if an threaded application is ported across several
platforms. Accordingly it is not recommended you trust scheduling behaviour to derive
any kind of strictly predictable coding results.

Java threads have priorities assigned to them. The default has the int value of 5 and has
the name, NORM_PRIORITYMAX_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( );
 

How many Thread?

Each thread has a default stack size of 400K. Peter Vander 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.
 

Thread States

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.
The thread methods that put a thread into this state include wait( ), sleep( ) and yield( ).
(The suspend( ) method has been deprecated so we don't count it. ) The blocked
condition is not caused by a method call. Instead, it is a behaviour that saves on cpu
cycles. The read( ) methods of the IO classes go into a blocked state if there is nothing
available to read. The final state is the dead state. When a run method of a thread is
completed, the thread is in the dead state. In the dead state, though execution is
completed the methods of that thread object remain available to be called.

Thread States
 
 Running   - in the running state  a thread is in control of the cpu
 Wait states   - caused by  wait( ), sleep( ), yield( ) or the blocked behaviour
 Ready    - not waiting for anything except the CPU
 Dead   - a thread's run method has completed

(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 premptive model the the bench is like
a 'free for all' where pushier players or couch favorites represent threads with higher
priority. They get back up to bat first regardless of the wait. Round-robin scheduling
is like the coach that is painfully fair. 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 and has left the dug out.
 

The Dead State

When run( ) returns the thread is dead. Dead threads are unusual conceptually. Though
they are no longer active their methods can still be called. It use to be that to kill a thread
the stop( ) method was called. A lot of old texts will show examples of the stop method
being called on a thread. Unfortunately there were serious problems with the stop( )
method and a few others so they are now deprecated. The recommendation now is 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;

The following table excepts from the API the explanation why stop( ), and the suspend
and resume( ) methods were deprecated.
 
  Major Thread Method Deprecations // excerpted from JDK API documentation


 void stop( ) -deprecated  - inherently unsafe. Stopping a thread with  Thread.stop 
 causes it to unlock all of the monitors that it has locked (as a natural consequence
 of the unchecked  ThreadDeath exception propagating up the stack). If any of the 
 objects previously protected by these monitors were in an inconsistent state, the
 damaged objects become visible to other threads, potentially resulting in arbitrary 
 behavior. Many uses of stop should be replaced by code that simply modifies 
 some variable to indicate that the target thread should stop running.  The target
 thread should check this variable regularly, and return from its run method in an 
 orderly fashion if the variable indicates that it is to stop running. If the target 
 thread waits for long  periods (on a condition variable, for example), the interrupt 
 method should be used to interrupt the wait. 

 void suspend( )  -deprecated. as it is inherently deadlock-prone. If the target 
 thread holds a lock on the monitor protecting a critical system resource when 
 it is suspended, no thread can access this resource until the target thread is 
 resumed. If the thread that would resume the target thread attempts to lock 
 this monitor prior to calling resume, deadlock results. Such deadlocks 
 typically manifest themselves as "frozen" processes.

 resume( ) -deprecated. -exists solely for use with suspend( ), which  has been 
 deprecated as it is prone to deadlock.



 For more see 'Why are Thread.stop, Thread.suspend  and Thread.resume Deprecated?.',-@ Sun 

The Thread class

Java was designed on a foundation which provided support for threads. Java depends
on a background thread called the garbage collector to automatically deallocate unused
memory. 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).
Java supplies these lightweight processes called thread 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 in the
java.lang package and so does not require any explicit package imports.

A thread object can be thought of as a virtual central processing unit or cpu. In this analogy
the thread's start method serves to turn the cpu on. The run method is to the thread process
what main is to a java program running in a command line process. 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 systems memory and
performance characteristics.

A Table Comparing Threads Parts to a Java Virtual Machine running an Application in main( )
 
 Virtual Machine  Thread
 central processing unit  Thread object
 power on   start( ) method
 main(  ) method   run( ) method

Details of Thread Actiivity 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. This method normally never returns.
The conventional way to call the method is via System.exit(0) where the 0 int
value is a status code that indicates a normal exit. Non-zero status codes indicate
abnormal halts.

Aside from the background threads such as the garbage collector and the event
thread when, the Java Virtual Machine starts a single non-daemon thread 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-deamon
threads have died. The non-daemon threads will have died either by having their
run( ) methods return or by throwing an exception that propogates beyond the name
scope of the run method.
 

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
environent. 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. Thead class has the following declaration.

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. When you override it it is declared public, returns void and takes no
arguments. It is inside the run( ) method that the work that is being given to the
thread is contained.

public interface Runnable{
           public abstract void run( );
           }

Two Approaches To Running Threads
 

There are two approaches to creating threads.You can either extend Thread
class and thereby inherit the Runnable behaviour. or you can implement
Runnable in a class to obtain thread behaviour. These two approaches can
be summarized as

1) Subclass Thread and override run( )
2) Target another object that implements Runnable
 
 

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 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. First consider the subclassing technique.
 

Subclass Thread

In summary the steps involved are as follows.

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( );
        }
     }

 // in case you don't override run the Thread class supplies a do-nothing version
 

Call another objects run( )

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.

1) Create a class which implements Runnable
2) Provide an instance of Runnable to a Thread constructor

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 Sample Showing a Runnable Object supplied to the 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( );
        }
    }

Key Thread Class Methods
 

yield( )

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 to set to a slightly lower
priority then the thread that needs to be checked occasionally and yield( ) is called
periodically to let the occasional thread to run.
 

sleep( )
A static method, which causes the currently executing string to 'time-out' for an approximate
time specified in milliseconds, or milliseconds and nanoseconds Time is approximate as the
thread re-enters the ready state and there is no guarantee when it will  run again. sleep( )
throws InterruptedException // As long as the exception is not thrown the method guarantees
a minimum amount of sleep time.
 
 

suspend( ) [deprecated] 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 so a suspend( ) followed by resume( ) in the same run method will never
resume(  ). resume( ) called on a thread that is not suspended has no effect
 
 

interrupt( )
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,

catch(InterruptedException ie) {
        break;
        }
 

join( )
This method causes the current thread to stop until the thread (on which the method was
invoked) is finished. This method provides a rudimentary form of communication between
threads as one thread is allowed to complete before the next thread is started.
 
 

blocking
Blocking is not a method, but a behaviour. 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).
 
 

setDaemon( )
This method makes a thread a daemon versus a user thread.
 
 daemon // around Waterloo-Kitchener  it's most often pronounced day - mon 


 Pronounced "demon." A UNIX program that executes in the background  ready to
 perform an operation when required. Functioning like an extension to the operating 
 system, a daemon is usually an unattended process that is initiated at startup. 
 Typical daemons are print spoolers and e-mail handlers or  a scheduler that starts 
 up another process at a designated time. The term comes from Greek mythology 
 meaning "guardian spirit."
                                                                                                            the TechEncylopodia

In Java a daemon thread is a service provider whose value is predicated on the presence
of a user thread. 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.

Thread Code Sample

The following example shows that when the threads have equal priority they more
or less get even turns 'at bat'. The first thread to get started gets a few turns in first.
If you uncomment the priority setting methods you can see how you can wait the
priority so one gets it's work done ahead of the other.
class Busy extends Thread{
public void run(){
 for(int i=0;i<20;i++)
 System.out.print("-Busy,Busy,Busy!-");
 }
}

class Occasional extends Thread{
public void run(){
  for(int i=0;i<20;i++)
 System.out.print("-Occasional!-");
 }
}

class RunBoth{
public static void main(String[] args){
 Busy b=new Busy();
 Occasional o=new Occasional();

  // b.setPriority(7);
  // o.setPriority(4);
   b.start();
   o.start();
 
 

The Thread Class

 Fields
 
 static int  MAX_PRIORITY  The maximum priority that a thread can have.
 static int  MIN_PRIORITY  The minimum priority that a thread can have.
 static int  NORM_PRIORITY  The default priority that is assigned to a thread.

 Constructors
 
Thread ( )   Allocates a new Thread object.
Thread (Runnable target)  Allocates a new Thread object.
Thread 
(Runnable target, String name) 
 Allocates a new Thread object.
Thread (String name)  Allocates a new Thread object.
Thread
(ThreadGroup group, Runnable target)
 Allocates a new Thread object.
Thread (ThreadGroup group, Runnable
target, String name)
 Allocates a new Thread object so that it has target as 
 its run object, has the specified  name as its name, 
 & belongs to the thread group referred to by group.
Thread (ThreadGroup group, String name)  Allocates a new Thread object.

 Methods
 
 static int activeCount( )  Returns the current # of active threads in this thread's thread group.
void checkAccess( )  Determines if the currently running thread has permission to modify
 this thread.
 static Thread 
 currentThread( )
 Returns a reference to the currently executing thread object.
void destroy( )  Destroys this thread, without any cleanup.
static void dumpStack( )  Prints a stack trace of the current thread.
static int enumerate
(Thread[] tarray)
 Copies into the specified array every active thread in this thread's 
 thread group and its subgroups.
ClassLoader 
getContextClassLoader( )
 Returns the context ClassLoader for this Thread.
String getName( )  Returns this thread's name.
int getPriority( )  Returns this thread's priority
ThreadGroup 
getThreadGroup( )
 Returns the thread group to which this thread belongs.
void interrupt( )  Interrupts this thread.
 static boolean 
 interrupted( )
 Tests whether the current thread has been interrupted.
 boolean isAlive( )  Tests if this thread is alive.
boolean isDaemon( )  Tests if this thread is a daemon thread.
boolean isInterrupted( )  Tests whether this thread has been interrupted.
void join( )  Waits for this thread to die. // 1of 3, also specify milli /& nano
 run( )  If this thread was constructed using a separate Runnable run 
 object, then that  Runnable object's run method is called; 
 otherwise, this method does nothing and returns.
void setContextClassLoader
(ClassLoader cl)
 Sets the context ClassLoader for this Thread.
void setDaemon(boolean on)  Marks this thread as either a daemon thread or a user thread.
 void setName(String name)  Changes the name of this thread to be equal to the argument name.
void setPriority
(int newPriority)
 Changes the priority of this thread.
 static void sleep
 (long millis)
 Causes the currently executing thread to sleep (temporarily cease
 execution) for specified milliseconds.// 1 of 2 also ( millis, nanos)
 void start( )  Causes this thread to begin execution; the Java Virtual Machine 
 calls the run method of this thread.
String toString( )  Returns a string representation of this thread, including the 
 thread's name, priority, and thread group.
 static void yield( )  Causes the currently executing thread object to temporarily 
 pause and allow other threads to execute.
  countStackFrames, resume, stop,& suspend are deprecated. notify,notifyAll & wait are inherited from Object