The simplest way to define
concurrent threads in Java is to have a class extend the built-in class Thread. Suppose
we have such a class, as follows, in which we define a function run() as
shown:
public class Parallel
extends Thread{
private int id;
public Parallel(int i){ //
Constructor
id = i;
}
public void run(){
for (int j = 0; j <
100; j++){
System.out.println("My
id is "+id);
try{
sleep(1000); //
Go to sleep for 1000 ms
}
catch(InterruptedException
e){}
}
}
}
Then, we can created objects of type Parallel
and “start” them off in parallel, as follows:
public class
TestParallel {
public static void
main(String[] args){
Parallel p[] = new
Parallel[5];
for (int i = 0; i <
5; i++){
p[i] = new Parallel(i);
p[i].start(); // Start off
p[i].run() in concurrent thread
}
}
The call p[i].start() initiates
the function p[i].run() in a separate thread. (Note that
if we write p[i].run() instead of p[i].start() we just
execute p[i].run() like any other function in the current thread—that
is, control is transferred to p[i].run() and when it finishes,
control passes back to the caller.)
Notice the function sleep(..)
used in run(). This is a static function
defined in Thread that puts the current thread to sleep for the
number of milliseconds specified in its argument. Any
thread can put itself to sleep, not just one that extends Thread. In
general, one would have to write Thread.sleep(..) if the
current class does not extend Thread. Observe that sleep(..)
throws InterruptedException (like wait(),
discussed earlier).
Of course, given the single inheritance
mechanism of Java, we cannot always extend Thread directly.
An alternative is to implement the interface Runnable. A class
that implements Runnable is defined in the same way as one
that extends Thread—we have to define a function public
void run()... However, to invoke this in parallel, we have to explicitly create a Thread from the Runnable
object by passing the reference to the object to the
Thread constructor.
Here is how we would rework the earlier example.
First the Runnable
class:
public class Parallel
implements Runnable{ // only
this line
// has changed
private int id;
public Parallel(int i){
... } // Constructor
public void run(){ ... }
}
Then, the class that uses
the Runnable class.
public class
TestParallel {
public static void
main(String[] args){
105
Parallel p[] = new
Parallel[5];
Thread t[] = new
Thread[5];
for (int i = 0; i <
5; i++){
p[i] = new Parallel(i);
t[i] = new Thread(p[i]); // Make a thread t[i] from p[i]
t[i].start(); //
Start off p[i].run() in concurrent thread
// Note: t[i].start(),
not p[i].start()
}
}
A thread can be in one of
four states:
• New: When it
has been created but not start()ed.
• Runnable: When it
has been start()ed and is available to be scheduled.
A Runnable thread need not be “running”—it
may be waiting to be scheduled. No guarantee is made about how scheduling is
done but almost all Java implementations now use time-slicing across running
threads.
• Blocked: The
thread is not available to run at the moment. This could happen for three
reasons:
1 . The
thread is in the middle of a sleep(..). It will then get
unblocked when the sleep timer expires.
2 . The
thread has suspended itself using a wait(). It will
get unblocked by a notify() or notfifyAll().
3 . The
thread is blocked on some input/output. It gets unblocked when the i/o succeeds.
• Dead: This
state is reached when the thread terminates.
# Interrupts
A thread can be
interrupted by another thread using the function interrupt(). Thus,
in our earlier example, we can write
p[i].interrupt();
to interrupt thread p[i]. This
raises an InterruptedException, which, as we saw, we must catch if the
thread is in sleep() or wait().
However, if the thread is actually
running when the interrupt arrives, no exception is raised! To identify that an
interrupt arrived in such a situation, the thread can check its interrupt
status using the function interrupted(), which returns a boolean
and clears the interrupt status back to false. Thus,
if we want to trap interrupts in p[i].run() both at the
sleep(..) and elsewhere, we should rewrite run() as
follows:
public void run(){
try{
j = 0;
while(!interrupted()
&& j < 100){
System.out.println("My
id is "+id);
sleep(1000); // Go to sleep for 1000 ms
j++;
}
catch(InterruptedException
e){}
}
}
}
It is also possible to check another
thread’s interrupt status using isInterrupted(). Thus t.isInterrupted()
returns a boolean. However, it does not clear the interrupt flag, unlike
interrupted(). Actually, interrupted() is a
static function that makes use of isInterrupted() to check
the flag of the current thread and then clears its interrupt flag.
Another useful function to spy on the
state of another thread is isAlive(). t.isAlive()
returns true if the thread t is
Runnable or Blocked and false if t is New or
Dead. Notice that you cannot use isAlive() to distinguish whether a
thread is Runnable or Blocked.
For historical reasons, Java also
supports a method stop() to kill another thread and suspend()
and resume() to unilaterally suspend and resume a thread (which
is not the same as the wait() and notify()/notifyAll()
construction). However, these are not supposed to be used because they
frequently lead to unpredictable conditions (when a thread dies abruptly) or
deadlocks (when suspended threads are not properly resumed).
- Static components and constants concept in programming language.
- Constructors in programming language.
- Callback functions in Java Programming language
- Abstract classes and Generic function in Java
- Monitors concept in Java Programming language
Post a Comment