Multi threading
In programming,
sometimes you need to do some tasks together (simultaneously), for example copying a file and showing the progress, or playing music
while showing some pictures as a slideshow.
If a program needs
to run (do) more than one task (thread) at a
time, that kind of a program is called a concurrent (multi-thread) program.
Each thread defines a separate path of execution. Multithreading enables
you to write very efficient programs that make maximum use of the CPU, because
idle time can be kept to a minimum.
Multitasking threads require less overhead than
multitasking processes. Processes are heavyweight tasks that require their own
separate address spaces. Inter process communication is expensive and limited.
Context switching from one process to another is also costly. Threads, on the
other hand, are lightweight. They share the same address space and
cooperatively share the same heavyweight process. Inter thread communication is
inexpensive, and context switching from one thread to the next is low cost.
Multithreading has several advantages over
Multiprocessing such as;
- Threads are lightweight compared to processes
- Threads share the same address space and therefore can share both data and code
- Context switching between threads is usually less expensive than between processes
- Cost of thread intercommunication is relatively low that that of process intercommunication
- Threads allow different tasks to be performed concurrently.
The Java Thread Model
Threads exist in several states. A thread can be running. It can be ready to run as soon as it gets CPU time. A running thread can be suspended, which temporarily suspends its activity. A suspended thread can then be resumed, allowing it to pick up where it left off. A thread can be blocked when waiting for a resource. At any time, a thread can be terminated, which halts its execution immediately. Once terminated, a thread cannot be resumed. Following diagram depicts the different states of a thread
![]() |
| States of a thread |
Thread Priorities
Java assigns to each thread a priority that
determines how that thread should be treated with respect to the others. Thread
priorities are integers that specify the relative priority of one thread to
another. As an absolute value, a priority is meaningless; a higher-priority thread
doesn’t run any faster than a lower-priority thread if it is the only thread
running. Instead, a thread’s priority is used to decide when to switch from one
running thread to the next. This is called a context switch. The rules that determine when a context switch takes place are simple:
·
A thread can voluntarily relinquish control: This
is done by explicitly yielding, sleeping, or blocking on pending I/O. In this
scenario, all other threads are examined, and the highest-priority thread that
is ready to run is given the CPU.
·
A thread can be preempted by a higher-priority
thread: In this case, a lower-priority thread that does not yield the processor is simply
preempted - no matter what it is doing - by a higher-priority thread.
Basically, as soon as a higher-priority thread wants to run, it does. This is called
preemptive multitasking.
Synchronization
Synchronization refers to ensuring that the
data remain consistent when more than one thread access it. Suppose there is a
method to increment the value of a variable x, and three threads are running
the method in parallel. CPU may be switched among the threads according to the
scheduling policy of the OS. Consider a situation when the first thread increments
the value of x but gets switched before the new value is updated. It may update
this after the other threads access and update the same variable x. This leads
to inconsistency. That is, you must prevent one thread from writing data while
another thread is in the middle of reading it. For this purpose, Java implements an elegant twist on an age-old model of
inter-process synchronization: the monitor.
The monitor is a control mechanism first defined
by C.A.R. Hoare. You can think of a monitor as a very small box that can hold
only one thread. Once a thread enters a monitor, all other threads must wait
until that thread exits the monitor. In this way, a monitor can be used to protect
a shared asset from being manipulated by more than one thread at a time.
Unlike other languages that support
multithreading. Java has no class “Monitor”; instead, each object has its own
implicit monitor that is automatically entered when one of the object’s synchronized
methods is called. Once a thread is inside a synchronized method, no other thread
can call any other synchronized method on the same object. This enables you to
write very clear and concise multithreaded code, because synchronization
support is built into the language.
Messaging
After you divide your program into separate
threads, you need to define how they will communicate with each other. Java
provides a clean, low-cost way for two or more threads to talk to each other,
via calls to predefined methods that all objects have. Java’s messaging system
allows a thread to enter a synchronized method on an object, and then wait
there until some other thread explicitly notifies it to come out.
The Thread Class and the Runnable Interface
Java’s multithreading system is built upon the Thread class, its methods, and its companion interface, Runnable. Thread encapsulates a thread of execution. Since you can’t directly refer to
the ethereal state of a running thread, you will deal with it through its
proxy, the Thread instance that spawned it. To create a new thread, your program will
either extend Thread or implement the Runnable interface.
The Main Thread
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. The main thread is important for two
reasons:
·
It is the thread from which other “child”
threads will be spawned.
·
Often, it must be the last thread to finish
execution because it performs various shutdown actions.
Creating a Thread
In the most general sense, you create a thread
by instantiating an object of type Thread. Java defines two ways in which this can be
accomplished:
·
You can implement the Runnable interface.
·
You can extend the Thread class, itself.
The following two sections look at each method,
in turn.
Implementing Runnable
The easiest way to create a thread is to create
a class that implements the Runnable interface. Runnable abstracts a unit of executable code. You can construct a thread on any
object that implements Runnable. To implement Runnable, a class need only
implement a single method called run( ), which is declared like this:
public void run( )
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 can. The only difference is that run( ) establishes the entry point for another, concurrent thread of execution
within your program. This thread will end when run( ) returns.
After you create a class that implements Runnable, you will instantiate an object of type Thread from within that class. Thread defines several
constructors. The one that we will use is shown here:
Thread(Runnable threadOb,
String threadName)
In this constructor, threadOb is an instance of a class that implements the Runnable interface. This defines where execution of the thread will begin. The
name of the new thread is specified by threadName.
After the new thread is created, it will not
start running until you call its start( ) method, which is declared
within Thread. In essence, start( ) executes a call to run( ). The start(
) method is shown here:
void start( )
Example:
The following program demonstrates the creation
of a simple thread.
MyRunnable.java
class MyThread
implements Runnable{
int a,i;
public void run(){
System.out.println("Inside
Thread”);
for(;i<10;i++){
System.out.println(a++);
}
}
}
class MyRunnable{
public static void main(String[] args){
Thread
t = new Thread(new MyThread());
t.start();
System.out.println("Back
in main");
}
}
Consider the code: Thread t = new Thread(new MyThread());
Passing an object of MyThread as the argument indicates that you want the new thread to
call the run( ) method on MyThread class.
Next, start( ) is called, which starts the thread of execution beginning at the run( ) method.
The output of the code is:
Creating Multiple Threads
The following program creates two threads which
on the same Runnable object. They operate on the shared variable a.
Example:
class MyThread
implements Runnable{
int a,i;
public void run(){
System.out.println("Inside
"+Thread.currentThread().getName());
try{
for(;i<10;i++){
Thread.sleep(1);
System.out.println(Thread.currentThread().getName()+"
"+a++);
}
}catch(InterruptedException
ie){}
}
}
class MyRunnable{
public static void main(String[] args){
MyThread m = new MyThread();
Thread t1 = new
Thread(m,"Alpha");
Thread t2 = new
Thread(m,"Beta");
t1.start();
t2.start();
try{
Thread.sleep(1000);
}catch(InterruptedException
ie){}
System.out.println("Back
in main");
}
}
In the above program we created two Thread
objects t1 and t2 passing the same MyThread
Object m. So the variables a and i are shared among both the threads. While creating the thread
objects we used the constructor Thread(Runnable
obj, String threadName). Here Alpha
is the name of the first thread and Beta
that of the second. Here we also use the static method sleep(long milliseconds) to make the thread sleep, i.e. get the
thread to blocked state. We have used the sleep()
method inside the run() method also,
so that the threads get switched. Inside the run() we have also used the getName()
method to access the name of the currently running thread. This method can only
be called using an object of Thread class, as we don’t have the object of the
current thread (here t1 or t2) we use the static method currentThread() which will return the current thread object. Remember
that static methods can be called using class name, without creating an object
of the class.
The output of the code is:

