Ch 3
Ch 3
Multithreading Concept
1
Processes and Threads
A multitasking operating system creates several processes and runs them on multiple
CPUs or the cores of a single CPU.
In the rare situation that you have a single-core CPU in your box, the OS will switch the
CPU between these processes, giving you the illusion of concurrently running
processes.
Processes are usually large and can be further split into smaller units of execution.
For example,
• A word processing application might perform a background spell check while the
user edits the document.
• A spreadsheet application may allow the user to interact with it while it performs
calculations in the background.
• To implement these kinds of features, the developer splits the process into
two units—one that is responsible for calculations and the other for handling
user interactions.
(a) Here multiple threads are running on multiple CPUs. (b) Here multiple threads share
a single CPU.
The operating system is responsible for scheduling and allocating resources to threads
3
Thread State
Threads can be in one of six states:
New Threads
When you create a thread with the new operator—for example, new Thread(r)—the
thread is not yet running. This means that it is in the new state.
When a thread is in the new state, the program has not started executing code inside of
it.
Runnable Threads
Once you invoke the start method, the thread is in the runnable state. A runnable
thread may or may not actually be running. It is up to the operating system to give the
thread time to run.
The details of thread scheduling depend on the services that the operating system
provides. 4
Preemptive scheduling systems give each runnable thread a slice of time to perform its
task.
When that slice of time is exhausted, the operating system preempts the thread and
gives another thread an opportunity to work.
When selecting the next thread, the operating system takes into account the thread
priorities.
Blocked Threads
When the thread tries to acquire an intrinsic object lock that is currently held by another
thread, it becomes blocked.
The thread becomes unblocked when all other threads have relinquished the lock and
the thread scheduler has allowed this thread to hold it
Waiting Threads
When the thread waits for another thread to notify the scheduler of a condition, it enters
the waiting state.
In practice, the difference between the blocked and waiting state is not significant. 5
Timed Waiting Threads
Several methods have a timeout parameter.
Calling them causes the thread to enter the timed waiting state.
This state persists either until the timeout expires or the appropriate notification has been
received
Terminated Threads
A thread is terminated for one of two reasons:
• It dies a natural death because the run method exits normally.
• It dies abruptly because an uncaught exception terminates the run method.
In particular, you can kill a thread by invoking its stop method.
That method throws a ThreadDeath error object that kills the thread. However, the stop
method is deprecated, and you should never call it in your own code.
6
Thread states 7
Thread Priorities
With several threads running on a system, you may want to prioritize their execution.
You do so by assigning a priority level to each thread. In Java, the thread priority levels
range from 1 to 10.
The priority 0 is reserved for the virtual machine. Java also provides a few predefined
constants for setting the thread priority.
The OS maintains a separate queue for all threads belonging to each priority level
8
Because threads with the higher priority level get the CPU first, this implies that a thread
with a lower priority will starve for CPU cycles forever if the higher-priority threads never
finish.
However, this is not exactly true. The OS periodically raises the priority of these
“starving” threads until they reach the currently executing thread priority level.
At this level, each thread will eventually get its time slice.
9
After the time slice is over, the thread will be returned to the queue of its original priority.
There are two types of threads in Java:
• Daemon threads
• Non-daemon (user) threads
A daemon thread terminates automatically as soon as the parent thread that created this
thread terminates.
A daemon is simply a thread that has no other role in life than to serve others.
Examples are timer threads that send regular “timer ticks” to other threads or threads
that clean up stale cache entries.
A daemon thread should never access a persistent resource such as a file or database
since it can terminate at any time, even in the middle of an operation.
10
A non-daemon thread, however, continues to live even when the parent dies.
As long as there is at least one thread alive, we say that the process is alive.
When all non-daemon threads along with the remaining daemon threads of an
application die, we say that the process is dead.
Every Java application has at least one non-daemon thread, which is the main thread.
When the program quits this thread or the user closes the application, the main thread
dies.
However, the process can continue to live if it has already spawned other non-daemon
threads.
Creating a Thread
Java implements thread functionality by using the following classes/interfaces:
• The interface Runnable
• The class Thread
• The class ThreadGroup
11
The Runnable interface abstracts a unit of executable code. You can construct a thread
on any object that implements the Runnable interface.
Runnable defines only one method called run( ), which is declared like this:
Inside run( ), you will define the code that constitutes the new thread.
It is important to understand that run( ) can call other methods, use other classes,
and declare variables just like the main thread.
The only difference is that run( ) establishes the entry point for another, concurrent
thread of execution within your program.
After you have created a class that implements Runnable, you will instantiate an object
of type Thread on an object of that class.
12
The Thread class has several constructors, which take in a variation of the following
parameters:
String name.
Every Thread object has a name associated with it. You can assign a thread any name
you like because the purpose of the name is to allow you to distinguish the various
threads you create.
If you do not assign your threads a name, the Thread class names them Thread0,
Thread1, Thread2, and so on.
Runnable target.
Associates a Runnable object as the target of the Thread.
ThreadGroup.
The group that the thread belongs to
long stackSize.
The number of bytes you want allocated for the size of the stack used by this thread.
13
Here is a simple procedure for running a task in a separate thread:
1. Place the code for the task into the run method of a class that implements the
Runnable interface. That interface is very simple, with a single method:
{
void run();
}
You simply implement a class, like this:
class MyRunnable implements Runnable
{
public void run()
task code
}
}
14
2. Construct an object of your class:
Runnable r = new MyRunnable();
When a Java program starts up, one thread begins running immediately.
This is usually called the main thread of your program, because it is the one that is
executed when your program begins.
Caution
Do not call the run method of the Thread class or the Runnable object.
Calling the run method directly merely executes the task in the same thread—no new thread
19
is started. Instead, call the Thread.start method. It will create a new thread that executes
It is possible to have a thread begin execution as soon as it is created.
Second, there is no need for MyThread to store the name of the thread since it is
possible to give a name to a thread when it is created.
22
Extending Thread
When a class extends Thread, it must override the run( ) method, which is the entry
point for the new thread.
It must also call start( ) to begin execution of the new thread.
It is possible to override other Thread methods, but doing so is not required.
Example
public class MyThread2 extends Thread {
// Construct a new thread.
MyThread2(String name) {
super(name); // name thread
start(); // start the thread
}
public void run() {
System.out.println(getName() + " starting.");
try {
23
for(int count=0; count < 10; count++) {
Thread.sleep(400);
System.out.println("In " + getName() +
", count is " + count);
}
}
catch(InterruptedException exc) {
System.out.println(getName() + " interrupted.");
}
System.out.println(getName() + " terminating.");
}
}
24
public class ExtendThread {
public static void main(String args[]) {
System.out.println("Main thread starting.");
MyThread2 mt = new MyThread2("Child #1");
for(int i=0; i < 50; i++) {
System.out.print(".");
try {
Thread.sleep(100);
}
catch(InterruptedException exc) {
System.out.println("Main thread interrupted.");
}
}
System.out.println("Main thread ending.");
}
}
25