You are on page 1of 15

Chapter 11

THREADS

A thread is defined as the path of execution of a program. A thread is a sequence of


instructions that is executed to define a unique flow of control. It is the smallest unit
of code. For example, a Central Processing Unit (CPU) performs various tasks
simultaneously, such as writing and printing a document, installing a software, and
displaying the date and time on the status bar. All these processes are handled by
separate threads.

A process that is made of one thread is known as single-threaded process. A process


that creates two or more threads is called a multithreaded process. For example, any
Web browser, such as Internet Explorer is a multithreaded application. Within the
browser, you can print a page in the background while you are scrolling through the
page. You can play audio files and watch animated images at the same time. Each
thread in a multithreaded program runs at the same time and has a different
execution path.

The microprocessor allocates memory to the processes that you execute. Each process
occupies its own address space or memory. However, all threads in a process occupy
the same address space. Multitasking is the ability to execute more than one task at
the same time. Multitasking can be divided into the following categories:
􀀃Process-based multitasking
􀀃Thread-based multitasking
Process-based Multitasking
A process is a program that is being executed by the processor. The process-based
multitasking feature of Java enables you to switch from one program to another so
quickly that it appears as if the programs are executing at the same time. For
example, process-based multitasking enables you to run the Java compiler and use
the text editor at the same time.
Thread-based Multitasking
A single program can contain two or more threads and therefore, perform two or more
tasks simultaneously. For example, a text editor can perform writing to a file and print
a document simultaneously with separate threads performing the writing and printing
actions. Also, in a text-editor, you can format text in a document and print the
document at the same time. Threads are called lightweight process because there are
fewer overloads when the processor switches from one thread to another. On the
other hand, when the processor switches from one process to another process the
overload increases.
A single-threaded application can perform only one task at a time. In such a situation,
you wait for one task to complete so that another can start. A process having more
than one thread is said to be a multi-threaded process. The various advantages of
multithreading are:
􀀃Improved performance: Provides improvement in the performance of the processor by
simultaneous execution of computation and Input/Output (I/O) operations.
􀀃Minimized system resource usage: Minimizes the use of system resources by using
threads, which share the same address space and belong to the same process.
􀀃Simultaneous access to multiple applications: Provides access to multiple applications
at the same time because of quick context switching among threads.
􀀃Program structure simplification: Simplifies the structure of complex applications, such
as multimedia applications. Sub programs can be written for each activity that makes
complex program easy to design and code.

The Thread Model in Java


Java uses threads to increase the efficiency of CPU by preventing wastage of CPU cycles.
In single-threaded systems, an approach called event loop with polling is used. Polling is
the process in which a single event is executed at a time.

In the event loop model, a single thread runs in an infinite loop till its operation is
completed. When this operation is completed, the event loop dispatches control to the
appropriate event-handler. No more processing can happen in the system until the event-
handler returns. This results in the wastage of the CPU time.

The java.lang.Thread class is used to construct and access individual threads in a


multithreaded application. You can create a multithreaded application using the Thread
class and the Runnable interface.

The Thread class contains various methods that can obtain information about the
activities of a thread, such as setting and checking the properties of a thread, causing a
thread to wait, and being interrupted or destroyed. You can make applications and classes
run in separate threads by extending the Thread class. A few methods defined in the
Thread class are:
􀀃getPriority(): Returns the priority of a thread.
􀀃isAlive(): Determines whether a thread is running.
􀀃sleep(): Makes the thread to pause for a period of time.
􀀃getName(): Returns the name of the thread.
􀀃start(): Starts a thread by calling the run() method.
The Main Thread
The first thread to be executed in a multithreaded process is called the main thread. The
main thread is created automatically on the start up of Java program execution.You can
access a thread using the currentThread() method of the Thread class. The following
syntax shows how to declare the currentThread() method:
public static Thread currentThread()
In the preceding syntax, the currentThread() method returns a reference to the executing
thread object. You can also control the main thread in the same manner as any other
thread by obtaining a reference to the main thread. You can use the following code to
show the execution of a thread using the methods in the Thread class:
class mainThreadDemo {
public static void main(String args[])
{
Thread t= Thread.currentThread();
System.out.println(" The current thread: " + t);
t.setName("MainThread");
System.out.println(" The current thread after name change : " +
t);
System.out.println(" The current Thread is going to sleep for 10
seconds");
try{
t.sleep(10000);
}
catch(InterruptedException e)
{System.out.println("Main thread interrupted");}
System.out.println(" After 10 seconds...........the current
Thread is exiting now.");
}
}
In the preceding code, reference to the current thread is obtained by calling the
currentThread() method and its reference is stored in the t variable. The setName()
method is called to set the name of the thread, and the information about the thread is
displayed. The main thread is then made to sleep for 10 seconds by using the sleep()
method, and after 10 seconds the thread terminates. The sleep() method may throw
InterruptedException and it is always written in the try-catch block. The
InterruptedException exception is thrown when another thread interrupts the sleeping
thread.
The various states in the life cycle of a thread are:
􀀃􀀃New
􀀃􀀃Runnable
􀀃Not Runnable
􀀃Terminated or Dead
The following figure shows the life cycle of a thread:
The New Thread State
When an instance of the Thread class is created, the thread enters the new thread state.
The following syntax shows how to instantiate the Thread class:
Thread newThread = new Thread(this, "threadName");
In the preceding syntax, a new thread is created. A new thread is an empty object of the
Thread class and no system resources, such as memory are allocated to it. You have to
invoke the start() method to start the thread. The following syntax shows how to declare
the start() method:
newThread.start();
When the thread is in the new state, no other method except the start() method can be
called, otherwise it throws IllegalThreadStateException.
The Runnable Thread State
When the start() method of a thread is invoked, the thread enters the runnable state. The
start() method allocates the system resources to the thread, schedules the thread, and calls
its run() method.
A single processor cannot execute more than one thread at a time, therefore it maintains a
thread queue. When a thread is started, a thread is queued up for the processor time and
waits for its turn to get executed. As a result, the state of the thread is said to be runnable
and not running.
The Not Runnable Thread State
A thread is not in the runnable state if it is:
􀀃Sleeping: A thread is put into the sleeping mode by calling the sleep() method. A
sleeping thread enters the runnable state after the specified time of sleep has elapsed.
􀀃Waiting: A thread can be made to wait for some specified condition to be satisfied by
calling the wait() method. The thread can be notified of the condition by invoking the
notify() method of the Thread class.
􀀃Being blocked by another thread: When a thread is blocked by an I/O operation, it
enters the not runnable state.
The Dead Thread State
A thread can either be dead or alive. A thread enters the dead state when the loop in the
run() method is complete. Assigning a null value to a thread object changes the state of
the thread to dead. The isAlive() method of the Thread class is used to determine whether
a thread has been started or not. You cannot restart a dead thread.
You create a thread by instantiating an object of Thread type. You can create a thread in
the following ways:
􀀃Implementing Runnable interface
􀀃Extending the Thread class
You can use the following code to create a thread by implementing the Runnable
interface:
class NewThread implements Runnable
{
Thread t;
NewThread()
{
t = new Thread(this, "ChildThread");
System.out.println("Child Thread:" + t);
t.start();
}
public void run()
{ // Implementing the run() method of the Runnable interface
System.out.println("Child Thread Started");
System.out.println("Exiting the child thread");
}
}
class ThreadClass
{
public static void main(String args[])
{
new NewThread();
System.out.println("Main thread Started");
try
{
Thread.sleep(5000);
}
catch(InterruptedException e)
{
System.out.println("The main thread interrupted");}
System.out.println("Exiting the main thread");
}
}
In the preceding code, the NewThread class implements the Runnable interface. A new
instance of the NewThread class is created in the ThreadClass. The constructor of the
NewThread class creates a new thread by passing two arguments, ChildThread and this.
The ChildThread is the name of the new thread. The start() method begins the execution
of a thread by calling the run() method. The new thread constructor after calling the
start() method returns to the main() method. The main thread prints a statement and
sleeps for five seconds that is equal to 5000 milliseconds. The child thread of the main
thread prints the statement in the run() method and
transfers the control to the main() method.

You can use the following code to create a thread by extending the Thread class:
class ThreadDemo extends Thread
{
ThreadDemo()
{
super("ChildThread"); // calls the superclass constructor
System.out.println("ChildThread:" + this);
start();
}
public void run()
{
System.out.println("The child thread started");
System.out.println("Exiting the child thread");
}
}
class ThreadDemoClass
{
public static void main(String args[])
{
new ThreadDemo();
System.out.println("The main thread started");
System.out.println("The main thread sleeping");
try
{
Thread.sleep(1000);
}
catch(InterruptedException e)
{
System.out.println("The main thread interrupted");
}
System.out.println("Exiting main thread");
}
}
In the preceding code, the ThreadDemo() class extends the Thread class. The
ThreadDemoClass creates an object of the ThreadDemo class. The constructor of
ThreadDemo class calls the super() method that sets the name of the child thread as child
thread.
The start() method calls the run() method for starting the execution of the child thread.
The constructor then returns the control to the main thread. The main thread executes two
print statements and sleeps for one second.

You can create multiple threads in a program by implementing the Runnable interface or
extending the Thread class. You can use the following code to create two child threads
other than the main thread:
class newThreadClass implements Runnable
{
String ThreadName;
newThreadClass(String name)
{
ThreadName = name;
Thread t = new Thread(this, ThreadName);
System.out.println("Thread created: " + t);
t.start();
}
public void run()
{
try
{
for(int i=1;i<=5;i++)
{
System.out.println(ThreadName + "loop :" + i);
Thread.sleep(100);
}
}
catch( InterruptedException obj)
{
System.out.println("Thread :" + ThreadName +
"interrupted");
}
System.out.println(ThreadName + "is exiting");
}
}
class MultipleThread
{
public static void main(String args[])
{
new newThreadClass("FirstChildThread");
new newThreadClass("SecondChildThread");
try
{
for(int i=1;i<=5;i++)
{
System.out.println("Main Thread loop:" + i);
Thread.sleep(300);
}
}
catch(InterruptedException obj)
{
System.out.println("Main thread is interrupted");
}
System.out.println("Main Thread is terminating now");
}
}
In the preceding code, the two child threads and the main thread share the memory of the
CPU. The main thread calls the sleep() method for 300 milliseconds.
Using the isAlive() Method
The isAlive() method is used to check the existence of a thread. Because the main thread
is the last thread to be executed, calling the sleep() method within the main() method with
a long sleep time ensures that all the child threads terminate prior to the main thread.

You can use the isAlive() method to find the status of a thread. The following syntax
shows how to declare the isAlive() method:

public final boolean isAlive()

In the preceding syntax, the isAlive() method returns true if the thread is runningand
returns false if the thread is new or is terminated. The thread can be in runnableor not
runnable state, if the isAlive() method returns true. You can use the followingcode to use
the isAlive() method:
class newThreadClass implements Runnable
{
Thread t;
newThreadClass()
{
t = new Thread(this,"ChildThread" );
System.out.println("Thread created: " + t);
t.start();
}
public void run()
{
try
{
for(int i=1;i<=5;i++)
{
System.out.println(t + "loop :" + i);
Thread.sleep(100);
}
}
catch( InterruptedException obj)
{
System.out.println("Thread :" + t + "interrupted");
}
}
}
class isAliveDemo
{
public static void main(String args[])
{
newThreadClass obj = new newThreadClass();
System.out.println(obj.t + "is alive ? : " +
obj.t.isAlive());
try
{
for(int i=1;i<=5;i++)
{
System.out.println("Main Thread loop:" + i);
Thread.sleep(200);
}
}
catch(InterruptedException e)
{
System.out.println("Main thread is interrupted");}
System.out.println(obj.t + "is alive ? : " +
obj.t.isAlive());
System.out.println("Main Thread is exiting");
}
}
In the preceding code, the isAlive() method is called on the thread to check whether
the thread is in running or dead state.

The Java Run-time Environment executes threads based on their priority. A CPU can
execute only one thread at a time. Therefore, the threads, which are ready for execution,
queue up for their turn to get executed by the processor. The threads are scheduled using
fixed-priority scheduling. Each thread has a priority that affects its position in the thread
queue of the processor. A thread with higher priority runs before threads with low
priority.
Thread priorities are the integers in the range of 1 to 10 that specify the priority of one
thread with respect to the priority of another thread. Execution of multiple threads on a
single CPU in a specified order is called scheduling. The Java run-time system executes
threads based on their priority.

The threads are scheduled using fixed priority scheduling. In fixed priority scheduling,
each thread has a priority that affects its position in the thread queue of the processor. A
thread with higher priority runs before threads with low priority.
Setting the Thread Priority
You can set the thread priority after it is created using the setPriority() method declared
in the Thread class. The following syntax shows how to declare the setPriority() method:
public final void setPriority(int newPriority)
In the preceding syntax, the newPriority parameter specifies the new priority setting for a
thread. The priority levels should be within the range of two constants, MIN_PRIORITY
and MAX_PRIORITY. The setPriority() method throws the IllegalArgumentException
exception if priorityLevel is less than MIN_PRIORITY and greater than
MAX_PRIORITY.

The thread can be set to a default priority, by specifying the NORM_PRIORITY constant
in the setPriority() method. MAX_PRIORITY is the highest priority that a thread can
have, MIN_PRIORITY is the lowest priority a thread can have; and NORM_PRIORITY
is the default priority set for a thread. You can use the following code to set priorities to
various threads:
class ChildThread implements Runnable
{
Thread t;
ChildThread(int p)
{
t = new Thread(this,"ChildThread" );
t.setPriority(p);
System.out.println("Thread created: " + t);
}
public void run()
{
try
{
for(int i=1;i<=5;i++)
{
System.out.println(t + "loop :" + i);
Thread.sleep(500);
}
}
catch( InterruptedException obj)
{
System.out.println("Thread :" + t + "interrupted");}
}
}
class PriorityDemo
{
public static void main(String args[])
{
ChildThread obj1 = new ChildThread(Thread.NORM_PRIORITY - 2);
ChildThread obj2 = new ChildThread(Thread.NORM_PRIORITY + 2);
ChildThread obj3 = new ChildThread(Thread.NORM_PRIORITY + 3);
//Starting the threads with different priority
obj1.t.start();
obj2.t.start();
obj3.t.start();
try
{
System.out.println("Main thread waiting for child
thread to finish");
obj1.t.join();
obj2.t.join();
obj3.t.join();
}
catch(InterruptedException e)
{
System.out.println("Main thread is interrupted");}
System.out.println(obj1.t + "is alive ? : " +
obj1.t.isAlive());
System.out.println(obj2.t + "is alive ? : " +
obj2.t.isAlive());
System.out.println(obj3.t + "is alive ? : " +
obj3.t.isAlive());
System.out.println("Main Thread is exiting");
}
}
When two threads need to share data, you must ensure that one thread does not change
the data used by the other thread. For example, if you have two threads, one that reads
your salary from a file and another that tries to update the salary, data corruption might
occur. Java enables you to coordinate the actions of multiple threads by using
synchronized methods or synchronized statements.
Synchronization of threads ensures that if two or more threads need to access a shared
resource then that resource is used by only one thread at a time. You can synchronize
your code using the synchronized keyword. You can invoke only one synchronized
method for an object at any given time.

Synchronization is based on the concept of monitor. A monitor, also known as a


semaphore is an object that is used as a mutually exclusive lock. All objects and classes
are associated with a monitor and only one thread can own a monitor at a given time. To
enter an object’s monitor, you need to call a method that has been modified with the
synchronized keyword.

The monitor controls the way in which synchronized methods access an object or class.
When a thread acquires a lock, it is said to have entered the monitor. The monitor ensures
that only one thread has access to the resources at any given time. To enter an object’s
monitor, you need to call a synchronized method.

When a thread is within a synchronized method, all the other threads that try to call it on
the same instance have to wait. During the execution of a synchronized method, the
object is locked so that no other synchronized method can be invoked. The monitor is
automatically released when the method completes its execution. The monitor can also be
released when the synchronized method executes the wait() method. When a thread calls
the wait() method, it temporarily releases the locks that it holds. In addition, the thread
stops running and is added to the list of waiting threads for that object.

The following figure shows how synchronization is maintained among threads:

The following code shows the implementation of synchronization among threads:


class Thread1
{
void call()
{
System.out.println("first statement");
try
{
Thread.sleep(1000);
}
catch(Exception e)
{
System.out.println("Error " + e);
}
System.out.println("second statement");
}
}
class Thread2 extends Thread
{
Thread1 t;
public Thread2(Thread1 t)
{
this.t = t;
}
public void run()
{
t.call();
}
}
public class NotSynchronized
{
public static void main(String args[])
{
Thread1 obj1 = new Thread1();
Thread2 Obja = new Thread2(obj1);
Thread2 Objb = new Thread2(obj1);
Obja.start();
Objb.start();
}
}
In the preceding code, three classes are used. The first class, Thread1 has the call()
method that includes two print statements. Within the print statements, the sleep() method
is called on the current object with a lapse time of 1 second.

The second class, Thread2 extends the Thread class. The Thread2 class has the run()
method that calls the call() method with an instance of the Thread1 class.

The third class, NotSynchronized creates two objects of the Thread2 class and starts
the thread corresponding to objects, Obja and Objb. The Thread1 and Thread2 call a
method on the same object at the same time.
You can serialize the access to the call() method to avoid the race condition. The call()
method is used by one thread at a time. This can be done by just prefixing the
synchronized keyword to the call() method. You can use the following code to use the
synchronized keyword:
class Thread1
{
synchronized void call()
{
System.out.println("first statement");
try
{
Thread.sleep(1000);
}
catch(Exception e)
{
System.out.println("Error " + e);
}
System.out.println("second statement");
}
}
class Thread2 extends Thread
{
Thread1 t;
public Thread2(Thread1 t)
{
this.t = t;
}
public void run()
{
t.call();
}
}
public class SynchronizedThreads
{
public static void main(String args[])
{
Thread1 obj1 = new Thread1();
Thread2 Obja = new Thread2(obj1);
Thread2 Objb = new Thread2(obj1);
Obja.start();
Objb.start();
}
}

Threads can communicate with each other. Multithreading eliminates the concept of
polling by a mechanism known as interprocess communication. For example, there are
two threads, thread1 and thread2. The data produced by thread1 is consumed by thread2.
Thread1 is the producer, and thread2 is the consumer. The consumer has to repeatedly
check if the producer has produced data. This is a waste of CPU time as the consumer
occupies CPU time to check whether or not the producer is ready with data. One thread
cannot proceed until the other thread has completed its task.
A thread may notify another thread that the task has been completed. This
communication between threads is known as interthreaded communication. The various
methods used in interthread communication are:
􀀃wait(): Informs the current thread to leave its control over the monitor and sleep for a
specified time until another thread calls the notify() method. The following syntax shows
how to declare the wait() method:
public final void wait() throws InterruptedException;
􀀃notify(): Wakes up a single thread that is waiting for the monitor of the object being
executed. If multiple threads are waiting, one of them is chosen randomly. The following
syntax shows how to declare the notify() method:
public final void notify()
􀀃notifyAll(): Wakes up all the threads that are waiting for the monitor of theobject.

You might also like