Threads

Thread API

"Imagine that you are using your favorite text editor on a large file. When it starts up, does it need to examine the entire file before it lets you edit? Does it need to make a copy of the whole file? Wouldn't it be nice for it to show you the first page, enabling you to begin editing, and somehow (in the background) complete the slower tasks necessary for initialization? Threads allow exactly this kind of within-the-program parallelism." from Java in 21 Days

What is a Thread? .

A thread represents a single process in execution on a system. Threads are sometimes referred to as light-weight processes or execution contexts. Typically, each thread controls a single aspect within a program, such as monitoring a particular input device or handling all of the disk I/O.

Has an execution context, program counter, stack, ...

A single-threaded program uses only one thread to control its execution. Many applications and applets are single-threaded.

If you see a browser page with two applets running at the same time, or scrolled your page while the applet continued running, then the browser is multithreaded.

Multithreaded applications (and applets) use several execution contexts to accomplish their tasks. They make use of the fact that many tasks contain separate and distinct sub-tasks. One thread can be used for each subtask.

A multithreaded program allows each thread to start and finish as quickly as possible; this behavior provides better response to real-time input.

Note that the vonNeumann machines (machines with single processors) are becoming obsolete fast! Multiple processor machines are here; threads are great experience for parallel processing and parallel algorithm considerations which can be used on these multiple processor machines.

Here are a couple of examples of SUN using Threads for use in Swing: Concurreny in Swing and Threads in Applets

Introducing Threads

SO, threads can be simple but also possibly dangerous.
First, let us look at the basics. There are two main techniques with which to instantiate threads one uses inheritance and the other implements an Interface. Then we will consider some of the problems.

A SimpleThread example:

Because applications go through main() when starting, this is a natural place to create and start threads. Examples:

The first line creates a new subclass of thread called T. In the second, the two arguments passed to TestThread (see below) represent the name of our thread and the time we want the thread to delay before printing its message.

Because we have direct control of our thread, we must start it directly as well:

t1.start();

Below is a first simple use of threads.

Manipulating Threads

t should contain a valid thread of execution. We control this thread in the run() method.

Once inside the run methood, you can execute statements as in any program. run() serves as the main() routine for threads. When run() finishes, so does the thread.

In these examples, we are pausing for a period of time (random (below) and 300 milliseconds (above))

sleep (300);

The sleep() method simply tells a thread to be quiet for (at least) the specified number of milliseconds. You can use sleep when you delay execution of a thread. The sleep() method does not take up system resources while the thread sleeps. Other threads can (will) continue to work.

Below is a another simple introduction to threads.

A simple multithread example to test the TestThread:

import java.util.Random;

Runnable

The other way to create a thread is to declare a class that implements the Runnable interface.

That class then implements the run method. An instance of the class can then be allocated, passed as an argument when creating Thread, and started.
See
Thread API for constructors of Threads

The program below creates a thread that prints 3 messages.

Notice the interface Runnable (remember interface and implement?)

To create a thread, you must subclass Thread so that it defines its own run() method,
OR
you must pass a Runnable object to the Thread constructor.

The interface specifies the run() method that is required for use with the Thread class. Any class that implements this interface can provide the "body" of a thread. By implementing the interface Runnable you declare your intention to run on a separate thread.

from tutorial

History

Ahhhhhhh deprecated notes below!
Note deprecated methods in
the thread API

Although SUN deprecated some thread methods, a user should be familiar with what they were and why they were deprecated.

Pausing a thread

Often the ability to suspend a thread without a specific time limit is useful. Suppose, for example, you are building an applet with an animation thread, you might want to provide the user with the option to pause the animation until the user wanted to resume.

You do not want to throw the animation away, you want to de-activate it. For this type of thread control you can use

t1.suspend();

This method does not halt the execution permanently. The thread is suspended indefinately until you activate the thread using

t1.resume();

A thread will automatically suspend() and then resume() when it's first blocked at a synchronized point and then later unblocked (when it is that threads turn to "run").

Stopping a thread

We can stop a thread with

t1.stop(); // stops the thread by throwing a ThreadDeath error.

This does not destroy the thread, but it halts execution. When a thread is stopped, the state of the thread object is set so that it is not restartable. Execution cannot be restarted by using t1.start(). The start() method won't return an exception condition, but the run() method also won't be called. The isAlive()method also won't return true.

In the examples shown, we did not need to explicitly stop the threads. We simply let them finish. A thread runs until the run() method returns or until the stop() method of its Thread object is called. More complex threaded examples will require control over each thread; the stop() method can be used therein.

If needed, you can test to see if your thread is "alive". A thread is alive if it has been started and has not been stopped.

t1.isAlive();           // returns true if t1 is alive

Life Cycles of a Thread

Why JavaSoft is Deprecating Thread.stop, Thread.suspend and Thread.resume and also look at the deprecated methods in the thread API


Multi-Thread Communications

Producers and Consumers

The idea is to design threads to use common objects, which each thread can manipulate independently of the other threads.

The classic thread communication example builds on a producer/consumer model: one thread produces some output; the other thread consumes (uses) whatever the output is.

Monitors

Monitors are important pieces of multithreaded applications because they keep the communications flowing.

Monitors will hold the shared information in a Shared Object and they usually perform the function of monitoring information transactions between two (or more) threads.

The data members in the Shared Object should be private to keep the Producer and Consumer from getting at the data directly. why? how?

Because...

Synchronized access methods stop producers and consumers from corrupting a shared object. While the producer is adding a data object to the Shared Object, the consumer cannot be taking one, and vice versa. (critical sections)

How does one add or use? The class that holds the data object has these synchronized methods (of course).

The synchronized keyword tells Java to make the block of code in the method thread safe. Only one thread can be allowed inside this method at once, and others have to wait until the currently running thread is finished.

Obvious Note: this implies that synchronizing large, long-running methods is almost always a bad idea.

This synchronization (remember semaphores?) is vital to maintaining the integrity of any Shared Object. The notify() method at the end of each access method signals any waiting process. The waiting process will try its access again.

yield() makes the current thread give up control to any other threads of equal priority that are waiting to run.

Typically the shared object should be a private instance variable.

Why private?

Why instance?

The private nature will keep the Producer and Consumer from getting the data directly. Direct data access can cause trouble. If, for example, the consumer tried to pull data out of an empty buffer, you would get unnecessary exceptions, or you could lock up the process.

If the variable were a class variable, you could have multiple threads modifying it by using different instances of the class.

Lab 2 uses threads and must use the producer, consumer, monitor pattern: Lab 2 and examples

More on synchronization and why have threads coming.