Jim Cheung

From Learning Java, 4th ed.

(note, I have some new notes about Java 8 concurrency)

Create

All execution in Java is associated with a Thread object ("main" thread).

A new thread is born when we create an instance of java.lang.Thread class.

Runnable interface defines a single, general-purpose run() method:

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

Every thread begins its life by executing the run() method in a Runnable object, which is the "target object" that was passed to the thread's constructor.

run() must be public, take no arguments, have no return value and throw no checked exceptions.

A newly born thread remains idle until we called 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 life of a thread. Once a thread starts, it continues running until the target object's run() method returns (or throws an unchecked exception).

simple example:

// this is the target object class
class Animation implements Runnable {
    boolean animate = true;
    public void run() {
        while ( animate ) {
            // draw Frames
            ...
        }
    }
}
Animation happy = new Animation("Mr. Happy");
// passing target object to Thread's constructor
Thread myThread = new Thread(happy);
myThread.start(); // start() executes the run()  method in target object

Another design option is to make our target class a subclass of a type that is already runnable.

Thread class itself conveniently implements the Runnable interface; it has its own run() method (Thread itself defines an emptyrun() method), which we can override directly:

class Animation extends Thread {
    boolean animate = true;
    // override
    public void run() {
        while ( animate ) {
            // draw Frames
            ...
        }
    }
}
Animation bouncy = new Animation("Bouncy");
bouncy.start();

The default constructor of the Thread class make itself the default target - Thread executes its own run() method when we call the start() method.

Alternatively, we can have Animation object start its thread when it is created:

class Animation extends Thread {
    Animation (String name) {
        start();
    }
    ...
}

Finally, we can build an adapter class to give us more control over how to structure the code.

It is particularly convenient to create an anonymous inner class that implements Runnable and invoikes an arbitrary method in our object:

class Animation {
    // an arbitrary method
    public void startAnimating() {
        // do setup, load images, etc.
        ...
        // create an anonymous inner class
        Thread myThread = new Thread ( new Runnable() {
            public void run() { drawFrames(); }
        } );
        // start a drawing thread
        myThread.start();
    }
    private void drawFrames() {
        // do animation
        ...
    }
}

We could also start the thread without saving a reference:

// Thread is Runnable too
new Thread() {
    public void run() { drawFrames(); }
}.start();

Control

Several methods let us explicitly control a thread's execution:

Deprecated methods:

These deprecated methods shouldn't be used in new code development. The problem with both stop() and suspend() is that they seize control of a thread's execution in an uncoordinated, harsh way.

A better way to affect the execution of a thread is by creating some simple logic in your thread's code to use monitor variables (flags), possibly in conjunction with the interrupt() method, which allows you to wake up a sleeping thread.

sleep()

We often need to tell a thread to sit idle:

try {
    // the current thread
    Thread.sleep( 1000 );
} catch ( InterruptedException e ) {
}

The sleep() method may throw an InterruptedException if it is interrupted by another thread via the interrupt() method.

join()

If you need to coordinate your activities with another thread by waiting for it to complete its task, you can use the join() method.

Calling a thread's join() method causes the caller to block until the target thread completes.

Alternatively, you can poll the thread by calling join() with a number of milliseconds to wait. This is a very coarse form of thread synchronization.

More powerful mechanism for coordinating thread activity is using wait(), notify() and java.util.concurrent package

interrupt()

interrupt() method wakes up a thread that is idle in a sleep(), wait(), or lengthy I/O operation.

Any thread that is not running continuously (not a "hard loop") must enter one of these states periodically and so this is intended to be a point where the thread can be flagged to stop.

When a thread interrupted, its interrupt status flag is set. This can happen at any time, whether the thread is idle or not.

The thread can test this status with isInterrupted() method, another form isInterrupted(boolean) accepts a Boolean value indicating whether or not to clear the interrupt status.

Death

a thread continues to execute until one of the following happens:

if none of these things occurs, the thread can live on, even after what is ostensibly the part of the application that created it has finished.

if we really want to create background threads that do simple, periodic tasks. use setDaemon() method. it marks a thread as a daemon thread that should be killed and discarded when no other nondaemon application threads remain.

Daemon threads are primarily useful in standalone java application and in the implementation of server frameworks. but not in component application such as applets. A browser or any other application can use ThreadGroup to contain all the threads created by subsystem of an application and then clean them up if necessary.

the AWT thread is not a daemon thread, so it doesn't exit automatically when other application threads have completed, and the developer must call System.exit() explicitly.