INTRODUCTION
A program under execution is called a process, Process is
complete, acquires a set of resources to run until it completes, and has its
own memory area. In a system that has merely a single execution core, then only
one process can execute at a time. Yet nowadays, more than one execution core
is in the system. But in the case of a single core only one process can run at
a time and it acquires all the required resources.
Multitasking can be of two types: process-based and, thread based.
This can be done in two conditions: one is that a computer has more than one
core processing unit (called multiprocessor), and the second is timesharing,
assigning a fixed time slice to each process.
The second approach to multitasking is thread-based. But before we
go in-depth with this approach, first understand what the thread is. A thread
is the smallest unit of the single program, which is dedicated to a specific
job. Thread is a lightweight process. Few resources are required to create a
thread rather than a process. Each thread has a separate path of execution.
Multitasking with a thread-based model provides an environment in which a
single program (application) can carry out more than one task simultaneously.
Multitasking is implemented by Multi-threading, or we can say that
multithreading is an extended version of multitasking using threads. Thus, a
specialized form of multitasking is called multithreading. Multi-threading
requires less overhead rather than a multitasking process. It reduces the
overheads of inter-process communication because threads are lightweight
processes. Context switching between the threads is also less costly. Because
threads share the same address space of the process it belongs. Multi-threading
facilitates writing an efficient program that makes optimum utilization of
resources including CPU.
THE
JAVA THREAD MODEL
The Java language and its run-time system were designed keeping in
mind about multithreading. Multithreading is best in all cases in contrast
with the single-thread model. The single-thread system uses an approach of
event loop with polling. According to this approach, a single thread in the
system runs in an infinite loop. Polling is the mechanism, that selects a
single event from the event queue to choose what to do next. As the event is
selected, the event loop forwards the control to the corresponding required
event handler. Nothing else can happen until the event handler returns. Because
of this CPU time is wasted. Here, only one part of the complete program
dominates the whole system, preventing the system from executing or starting
any other process. In a single-thread model, one thread blocks all other
threads until its execution completes. On the other waiting or idle thread can
start and acquire the resource which is not in use by the current thread. This
causes the wastage of resources.
Java's multithreading provides benefits in this area by
eliminating the loop and polling mechanism. One thread can be paused without
stopping the other parts of the program. If any thread is paused or blocked,
still other threads continue to run.
As the process has several states, similarly a thread exists in
several states. A thread can be in the following states:
Ready to run (New): First time as soon as it gets CPU time.
Running: Under execution.
Suspended: Temporarily not active
or under execution.
Blocked: Waiting for resources.
Resumed: Suspended thread
resumed, and started from where it left off.
Terminated: Halts the execution immediately and never resumes.
Java thread model can be defined in the following three sections:
- Thread Priorities
Each thread has its own priority in Java. Thread priority is an absolute integer value. Thread priority decides only when a thread switches from one running thread to the next, called context switching. Priority does increase the running time of the thread or gives faster execution.
- Synchronization
Java supports asynchronous multithreading, any number of threads can run simultaneously without disturbing others to access individual resources at different instants of time or shareable resources. But sometimes it may be possible that shareable resources are used by at least two threads or more than two threads, one has to write at the same time, or one has to write and the other thread is in the middle of reading it. For such types of situations and circumstances, Java implements a synchronization model called monitor. The monitor was first defined by C.A.R. Hoare. You can consider the monitor as a box, in which only one thread can reside. As a thread enters in monitor, all other threads have to wait until that thread exits from the monitor. In such a way, a monitor protects the shareable resources used by it being manipulated by other waiting threads at the same instant of time. Java provides a simple methodology to implement synchronization.
- Messaging
A program is a
collection of more than one thread. Threads can communicate with each other.
Java supports messaging between the threads with lost cost. It provides methods
to all objects for inter-thread communication. As a thread exits from the synchronization state, it notifies all the waiting threads.
UNDERSTANDING THREADS
In Java multithreading is built upon two important entities given by the language: one is Thread class with its method, and the second is the Runnable interface. The Runnable interface defines only a single method run(), which contains the code executed by the thread in the classes it will be implemented. A Runnable object is passed to the Thread constructor. Another entity is the Thread class, which is the subclass of the Runnable interface. It implements Runnable, though its run() method does nothing. As such you can not refer to the insubstantial state of any running thread, you have to deal with the proxy of it. Thread encapsulates the thread of execution so that you must have an instance of Thread. For this, either extend the Thread class or implement the Runnable interface. The Thread class defines several purpose methods, a few of which are discussed below:
THE MAIN THREAD
As any Java program
comes under execution, the first thread starts immediately, called the main thread.
There are two important's in the main thread as follows:
- Ø
It is the parent of all
the threads of the program and all other "child" threads will be
spawned from it.
- Ø
It must be the last
thread to finish the execution of the program.
As your program starts, the main thread is created automatically, under the control of the Thread object. But, if you want the reference of the main thread then there is a static method curentThread() of the Thread class, which returns the reference of the thread in which it is called. Its general form is shown here: static Thread current Thread()
Example:
Output
Current thread: Thread [main, 5, main]
New name of main Thread: Thread [Main Thread Demo, 5, main]
1 2 3 4 5 6 7 8 9 10
Output is showing three
line statement. In the first statement within square brackets "[]" the first
value is the name of thread "main", the second is priority "5"
and the last is the name of threadgroup "main", the current (main)
thread belongs to. Similarly, in the second printed statement first value is the name of the thread after modification "Main Thread Demo", the second is
priority "5" and the last is the thread group name "main". The default
created group by Java is "main". In the last it will print 1 to 10
and each digit after 0.5 seconds. In the above example, setName()
is used to change the
name of the thread. You can get the name of the thread by calling getName(). Both of these methods are of Thread class.
Their prototype is given below:
final void setName
(String threadName)
final String getName()
To give a pause to the
thread sleep() method is used in the given example. The
argument passed to the sleep() method is in
milliseconds. There are two versions of sleep() methods of Thread class
as follows:
static void sleep (long
time_in_milliseconds) throws InterruptedException
static void sleep
(long time_in_milliseconds, int additional_nanoseconds)
throws
InterruptedException
CREATING
A THREAD
In Java, a user-defined thread can be created to implement the
Runnable interface. The Runnable interface has only one method run() that you must have to implement in your class, that you want to create
as a thread. The run() is the method in which that code is written, which is counted as a thread task.
The content of the run() method will be counted as a thread portion, but the method written
outside the run() counts as part of the
main thread. Both the new thread and the main thread can run concurrently. The thread
terminates with the termination of the run method. Control is returned to the
caller method of the run method, or can say from where it starts. The run() method should not be called directly, the start()
method of the thread class
is called, and that is responsible for calling run() for the corresponding thread.
Another way to create a thread is to inherit the Thread class.
Thread class has several methods. Few of them are static and few are
non-static. As per the need you can override non-static methods. But the run() method must override, because it defines new thread functionality.
EXTENDING
THREAD
A new thread is created by creating a new class that extends
Thread and then creates an instance of that class. The extending class must
override the method run(), which is the entry point of the new thread (user-defined). To
begin the execution of the new thread, it must call the start() method. Inside the run() method, you'll write the code, which is considered
as the functionality of the thread. The run() method can call other methods of the same class or other class
using their objects. It is an entry point of the thread. As the run() method returns (exit or terminate) the thread ends.
Example:
There are two output of the
same thread code. Because it is not always sure that a thread executes in the
same manner. The output can be same or vary every time. The super() inside the NewThreadDemo constructor invokes the
following form of Thread constructor:
public
Thread (String thread_Name)
IMPLEMENTING
RUNNABLE
By implementing the
Runnable interface the thread creation is the easiest way. You can construct a thread
on any type of object that implements Runnable. To implement the Runnable
interface, a new class needs only to implement the run()
method. When you implement the Runnable interface then create an instance
of Thread from within that class. The Thread class has several constructors.
public Thread( )
public Thread ( String thread Name)
public Thread (Runnable threadobi)
public Thread (Runnable threadobi, string thread_Name)
public Thread (ThreadGroup groupobj, Runnable threadobj )
public Thread (ThreadGroup groupobj, Runnable threadObj, string
name)
After the new thread is
created, the start(
) method has to be used to start
running, otherwise it will not be started. In essence, start( )
executes a call to run( ).
Example:
MULTITHREADING
Till the last section, we've studied a single
thread that is created using the Runnable interface or Thread class. You can spawn
as many threads as you want.
Example:
Four chìld threads are created in the program, they run in the order in which those get the CPU time by the run-time system.
About join() and
isAlive()
In
the immediately above example there is a problem that the main thread is exited
before its child thread. Conceptually and logically the parent thread must die
or exit after all its child thread exits. Maybe the parent thread works have
been completed, but still, it has to wait for its child thread to complete its
task and exit. This can be possible, by join() method, All child threads have to join,
to prevent the main or parent thread exit before them. Now main or parent
thread must wait until all child thread exits.
The
isAlive () method is used to determine whether a given
thread is finished or running. If isAlive() returns
true means the thread is running, else returns false means the thread is finished.
Example:
THREAD PRIORITIES
Priority
allows the scheduler to make the decision about when the thread should be allowed to
run, and in which order. The higher-priority threads get more CPU time than
lower-priority threads. A lower-priority thread can be preempted by higher
higher-priority thread. The threads having equal priority get equal CPU time. To set a
thread's priority, use the setPriority() method,
which belongs to the Thread class. Prototypes are as
final
void setPriority (int priorityValue)
Here,
priorityValue
gives the new priority for the calling thread. The value of priorityValue must
be
within
the range MIN_PRIORITY and MAX_PRIORITY. The values of these Constants are 1
and 10, respectively. A thread default priority is NORM_PRIORITY, which is
currently 5.
These
priority constants are defined as final variables within Thread. You can get the current priority value of the thread by calling the getPriority( ) method of Thread,
shown here.
final int getPriority( )
Example:
public
class Main
{public
void setPrioritiesOnThreads ()
{
Thread
thread1 = new Thread (new TestThread (1) );
Thread
thread2 = new Thread (new TestThread(2 ) );
thread1.start
();
thread2.start
() ;
try
{
thread1.join()
;
threađ2.
join() ;
}
catch
(InterruptedException ex)
{
ex.
print StackTrace ();
}
System.out.println
("Done.");
}
public
static void main (String [] args )
{
new
Main() . setPriorities0nThreads () ;
}
class
TestThread implements Runnable
{
int
id;
public
Test Thread (int id)
{
this.
id = id;
}
public
void run()
{
for
(int i 1; i < 10; i++)
{
System.
out. println ( "Thread" +id +":"+ i);
}
}
}
}
Output:
The
output is without priority assigning to the thread. Both thread are executing
not in exact order, but executing concurrently. If we assign the priority to
the thread then the code is given below.
Example:
public
class Main
{public
void setPrioritiesOnThreads ()
{
Thread
thread1= new Thread(new TestThread(1) ) ;
Thread
thread2 = new Thread (new Test Thread (2) );
thread1
. setPriority (Thread . MAX_ PRIORITY) ;
thread2
. setPriority (Thread . MIN_PRIORTY) ;
threadl
. start () ;
thread2
. start () ;
try
{
thread1.
join() ;
thread2
. join () ;
}
catch
(InterruptedException ex)
{
ex.printStackTrace
() ;
}
System.
out .println ("Done. ");
}
public
static void main (String[ ]args)
{
new
Main () . setPrioritiesOnThreads ();
}
class
TestThread implements Runnable
{
int
iđ;
public
TestThread(int id)
{
this.id
= id;
}
public
void run()
{
for
(int i = 1; i <= 10; i++)
{
System.
out.print ln("Thread" + id + ":" +i);
}
}
}
}
Now thread1 has the highest priority so it executes first.
SYNCHRONIZATION
When
two or more threads want to access a shared resource, then it must ensure that
the resource will be used by only one thread at an instant time. The
mechanism of this process is called synchronization. Synchronization is the
concept of the monitor or semaphore. Monitor works as mutex and is restricted to one
thread to own a monitor at a given time. As the thread acquires the lock, all
the threads that want to acquire the monitor will be suspended. As the first
thread exits from the monitor, one thread will acquire the monitor from the waiting
list of threads.
Synchronization
of code can be done in two ways, but both use synchronized keywords.
·
Using
synchronized method
·
Using
synchronized statement
Example:
public
class SynchronizedMethodDemo extends object
{
Private
static int c=1;
Private
static void print (String msg)
{
String
threadName= Thread. currentThread () .getName();
System.out.println
(threadName + ":"+msg);
}
public
static synchronized int getCount ()
{int
i=c;
c++;
return
i;
}
public
static void main (String [] args)
{
try
{
Runnable
runnable = new Runnable () { public void run()
{
System.out.println
("count=" + getCount ());
}
};
Thread
thread1 = new Thread (runnable, "Thread1") ;
thread1.
start ();
Thread.
sleep (500) ;
Thread
thread2 = new Thread (runnable, "Thread2 ") ;
thread2.
start () ;
Thread.
sleep (500) ;
Thread
thread3=
new
Thread (runnable, "Thread3") ;
thread3
. start () ;
Thread.sleep(500);
Thread
thread4= new Thread (runnable, "Thread4");
thread4.start();
}
catch
(Exception x)
{
}
}
}
INTER-THREAD COMMUNICATION
If we talk about the
mechanism of synchronization, then as one thread exits from the monitor it
must inform the waiting threads that it has left the monitor, now suspended
thread can proceed to acquire, the lock on the resources or enter in the
monitor. If that is not possible then the waiting thread will always be in the
waiting list. So, to solve this problem threads must communicate with each
other. Java provides a set of methods by which they can communicate with each
other. Object class has some final methods for such purposes. All these methods
can be called only from the synchronized context.
- wait( ) tells the calling thread to leave the monitor and go to sleep until some other thread enters the same monitor and calls notify().
- notify( ) give a wake up signal or call to the first thread that is called wait( ) on the same object
- notify All() gives a wake-up signal or call to all the threads that called wait( ) on the on the same object. The highest priority thread will run first.
These methods are
declared within Object, as shown here:
final void wait( ) throws InterruptedException
final void notify ()
final void notifyAll( )
Example:
No comments:
Post a Comment