2016-08-08

Java Thread

Understanding Threads

A thread is a single sequence of executable code within a larger program. All the programs shown so far in this book have used just one thread — the main thread that starts automatically when you run the program. However, Java lets you create programs that start additional threads to perform specific tasks.

Understanding the Thread class

The Thread class lets you create an object that can be run as a thread in a multi-threaded Java application. The Thread class has quite a few constructors and methods, but for most applications you only need to use the ones listed in Table.

 Constructors and Methods of the Thread Class
Constructor                        Explanation
Thread()                          The basic Thread constructor without
                                                 parameters. This constructor simply creates
                                                 an instance of the Thread class.

Thread(String name)         Creates a Thread object and assigns
                                                the specified name to the thread.

Thread(Runnable target) A more advanced constructor that lets
                                                 you turn any object that implements an
                                                API interface called Runnable into a
                                                thread. You see how this constructor is
                                                used later in this chapter.

Thread(Runnable target, Creates a thread from any object that
                  String name)   implements Runnable and assigns the
                                                specified name to the thread.

static int activeCount()         Returns the number of active threads.

static int enumerate         Fills the specified array with a copy of
(Thread[] t)                         each active thread. The return value is
                                                the number of threads added to the array.

String getName()                Returns the name of the thread.

int getPriority()        Returns the thread’s priority.

void interrupt()        Interrupts this thread.

boolean isInterrupted()       Checks to see if the thread has been
                                                interrupted.



void setPriority(int priority) Sets the thread’s priority.

void setName(String name) Sets the thread’s name.

static void Sleep        Causes the currently executing thread
(int milliseconds)                to sleep for the specified number of
                                                milliseconds.

void run()                 This method is called when the thread is
                                                started. Place the code that you want the
                                                thread to execute inside this method.

void start()                 Starts the thread.

static void yield()                 Causes the currently executing thread to
                                                yield to other threads that are waiting to
                                                execute.

Thread life cycle


Extending the Thread class

The easiest way to create a thread is to write a class that extends the Thread class. Then, all you have to do to start a thread is create an instance of your thread class and call its start method.

For example, Listing 1 is a version of the CountDownClock class that extends the Thread class.
LISTING 1-1:THE COUNTDOWNCLOCK CLASS (VERSION 1)
public class CountDownClock extends Thread 
{
      public void run() 
      {
for (int t = 20; t >= 0; t--)
{
  System.out.println(“T minus “ + t);
                 try {
         Thread.sleep(1000); 
                        }
catch (InterruptedException e) {}
        }
     }
}

The CountDownClock class extends the Thread class. Thread is defined in the java.language package, so you don’t have to provide an import statement to use it.
The CountDownClock class has a single method, named run. This method is called by Java when the clock thread has been started. All the processing done by the thread must either be in the run method or in some other method called by the run method.
The CountDownClock class uses the sleep method to pause for one second. Because the sleep method throws InterruptedException, a try/catch statement handles this exception. If the exception is caught, it is simply ignored.
At some point in its execution, the run method must either call sleep or yield to give other threads a chance to execute.

Creating and starting a thread

After you define a class that defines a Thread object, you can create and start the thread. For example, here’s the main class for the first version of the countdown application:
public class CountDownApp
{
   public static void main(String[] args)
   {
     Thread clock = new CountDownClock();
     clock.start();
   }
}
Here, a variable of type Thread is declared, and an instance of the Count
DownClock is created and assigned to it. This creates a thread object, but
the thread doesn’t begin executing until you call its start method.

When you run this program, the thread starts counting down in one second increments, displaying messages such as the following on the console:
T-minus 20
T-minus 19
T-minus 18
And so on, all the way to zero. So far, so good.

The Runnable Interface :  Other Way to be Threaded

For the threads that trigger specific countdown events such as flooding the launchpad, starting the events, or lifting off, I create another class called LaunchEvent. This class uses another technique for creating and starting threads, one that requires a few more lines of code but is more flexible.
The problem with creating a class that extends the Thread class is that a class can have one superclass. What if you’d rather have your thread object extend some other class? In that case, you can create a class that implements the Runnable interface rather than extends the Thread class. The Runnable interface marks an object that can be run as a thread. It has only one method, run, that contains the code that’s executed in the thread. (The Thread class itself implements Runnable, which is why the Thread class has a run method.

Using the Runnable interface

To use the Runnable interface to create and start a thread, you have to do
the following:
1. Create a class that implements Runnable.
2. Provide a run method in the Runnable class.
3. Create an instance of the Thread class and pass your Runnable
object to its constructor as a parameter.
A Thread object is created that can run your Runnable class.
4. Call the Thread object’s start method.

The run method of your Runnable object is called, which executes in a
separate thread.
The first two of these steps are easy. The trick is in the third and fourth  steps, because you can complete them several ways. Here’s one way, assuming that your Runnable class is named RunnableClass:

RunnableClass rc = new RunnableClass();
Thread t = new Thread(rc);
t.start();
Java programmers like to be as concise as possible, so you often see this compressed to something more like this:
Thread t = new Thread(new RunnableClass());
t.start();
or even just this:
new Thread(new RunnableClass()).start();
This single-line version works provided you don’t need to access the thread
object later in the program.









public class LaunchEvent implements Runnable 
{
   private int start;
   private String message;
   
   public LaunchEvent(int start, String message)           //Constructor 
   {
      this.start = start;
      this.message = message;
   }

   public void run()                               // Method Overriding
   {
      try {
             Thread.sleep(20000 - (start * 1000)); 
             }
      catch (InterruptedException e) {}
      System.out.println(message); 
   }
}

In the run method, the Thread.sleep method is called to put the thread to sleep until the desired countdown time arrives. This length of time the thread should sleep is calculated by the expression  20000-(start * 1000). The countdown clock starts at 20 seconds, which is 20,000 milliseconds. This expression simply subtracts the number of milliseconds that corresponds to the desired start time from 20,000. Thus, if the desired start time is 6 seconds, the sleep method sleeps for 14,000 milliseconds — that is, 14 seconds.
When the thread wakes up, it displays the message passed via its constructor on the console.

Using the CountDownApp class
Now that you’ve seen the code for the LaunchEvent and CountDown
Clock classes, Listing 3 shows the code for a CountDownApp class that
uses these classes to launch a space shuttle.
LISTING 1-3:THE COUNTDOWNAPP CLASS (VERSION 1)
public class CountDownApp
{
public static void main(String[] args)
     {
Thread clock = new CountDownClock(); 
Runnable flood, ignition, liftoff;
flood = new LaunchEvent(16, “Flood the pad!”);
ignition = new LaunchEvent(6, “Start engines!”);
liftoff = new LaunchEvent(0, “Liftoff!”);
clock.start(); 
new Thread(flood).start(); 
new Thread(ignition).start();
new Thread(liftoff).start();
      }
}



Synchronizing Methods

Whenever you work on a program that uses threads, you have to consider the nasty issue of concurrency. In particular, what if two threads try to access a method of an object at precisely the same time? Unless you program carefully, the result can be disastrous. A method that performs a simple calculation returns inaccurate results. In an online banking application, you might discover that some deposits are credited twice and some withdrawals aren’t credited at all. In an online ordering system, one customer’s order might get recorded in a different customer’s account.
The key to handling concurrency issues is recognizing methods that update
data and that might be called by more than one thread. Once you identify
those methods, the solution is simple: You just add the synchronized keyword
to the method declaration, like this:
public synchronized void someMethod()...
This tells Java to place a lock on the object so that no other methods can
call any other synchronized methods for the object until this method finishes.
In other words, it temporarily disables multithreading for the object.
The tough part is knowing which methods to synchronize. When I said that
any method that updates data can be synchronized, I didn’t just mean any
method that updates a database. Any method that updates instance variables
is at risk and needs to be synchronized. That’s because when two or
more threads run a method at the same time, the threads share a common
copy of the method’s instance variables.
Even methods that consist of just one line of code are at risk. For example,
consider this method:
int sequenceNumber = 0;
public int getNextSequenceNumber()
{
return sequenceNumber++;
}
You’d think that because this method has just one statement, some other
Thread could not interrupt it in the middle. Alas, that’s not the case. This
method must get the value of the sequenceNumber field, add 1 to it, save
the updated value back to the sequenceNumber field, and return the value.
In fact, this single Java statement compiles to 11 bytecode instructions. If the
thread is preempted between any one of them by another thread calling the
same method, the serial numbers get munged.
For safety’s sake, why not just make all the methods synchronized? There
are two reasons:
✦ It takes time to synchronize methods. Java has to acquire a lock on the
object being synchronized, run the method, and then release the lock.
But before it can do that, it has to check to make sure some other thread
doesn’t already have a lock on the object. All of this takes time.
✦ More importantly, synchronizing all your methods defeats the purpose
of multithreading. So you should synchronize only those methods that
require it.
The synchronized keyword doesn’t block all access to an object. Other
threads can still run unsynchronized methods of the object while the
object is locked.
The Object class provides three methods that can let synchronized objects
coordinate their activities. The wait method puts a thread in the waiting state
until some other thread calls either the object’s notify or (more commonly)
notifyAll method. These methods are useful in situations where one thread
has to wait for another thread to do something before it can proceed. The
classic example is a banking system where one thread makes withdrawals
and the other makes deposits. If a customer’s account drops to zero, the
thread that makes withdrawals can call wait. Then, the thread that makes
deposits can call notifyAll. That way, each time a deposit is made, the
withdrawal thread can recheck the customer’s account balance to see if it
now has enough money to make the withdrawal.

Threadus Interruptus

You can interrupt another thread by calling its interrupt method, provided
you have a reference to the thread. For example:
t.interrupt();
Here, the thread referenced by the t variable is interrupted. Now, all the
interrupted thread has to do is find out that it has been interrupted and
respond accordingly. That’s the topic of the following sections.
Finding out if you’ve been interrupted
As you’ve already seen, several methods of the Thread class, including
sleep and yield, throw InterruptedException. Up until now, I told
you to simply ignore this exception. And in many cases, that’s appropriate.
However, many (if not most) threads should respond to Interrupted
Exception in one way or another. In most cases, the thread should terminate
when it’s interrupted.
Unfortunately, finding out if a thread has been interrupted isn’t as easy as it
sounds. InterruptedException is thrown when another thread calls the
interrupt method on this thread while the thread is not executing. That’s
why the methods that can cause the thread to give up control to another
thread throw this exception. That way, when the thread resumes execution,
you know it was interrupted.
However, the yield and sleep methods aren’t the only way for control to
be wrested away from a thread. Sometimes, the thread scheduler just steps
in and says, “You’ve had enough time, now it’s someone else’s turn to play.”
If that happens, and then some other thread calls your thread’s interrupt
method, InterruptedException isn’t thrown. Instead, a special flag
called the interrupted flag is set to indicate that the thread was interrupted.
You can test the status of this flag by calling the static interrupted
method.
Unfortunately, that means your threads have to check twice to see if they
have been interrupted. The usual way to do that is to follow this form:
public void run()
{
boolean done = false
boolean abort = false;
while(!done)
{
// do the thread’s work here
// set done to true when finished
try
{
sleep(100); // sleep a bit
}
catch(InterruptedException e)
{
abort = true;
}
if (Thread.interrupted())
abort = true;
if (abort)
break;
}
}
Here, the abort boolean variable is set to true if InterruptedException
is thrown or if the interrupted flag is set. Then, if abort has been set to true, a
break statement is executed to leave the while loop. Of course, this scheme
has a million variations. But this one works in most situations.

Aborting the countdown

To illustrate how you can interrupt threads, Listing 1-5 shows yet another
version of the countdown application. This version aborts the countdown if
something goes wrong with any of the launch events.
To simplify the code a bit, I assume that things aren’t going well at NASA,
so every launch event results in a failure that indicates to abort the countdown.
Thus, whenever the start time for a LaunchEvent arrives, the
LaunchEvent class attempts to abort the countdown. It goes without
saying that in a real launch control program, you wouldn’t want to abort
the launch unless something actually does go wrong.
LISTING 1-5:THE COUNTDOWN APPLICATION WITH ABORTS
import java.util.ArrayList;
public class CountDownApp ➞ 3
{
public static void main(String[] args)
{
CountDownClock clock = new CountDownClock(20);
ArrayList<Runnable> events = new ArrayList<Runnable>();
events.add(
new LaunchEvent(16, “Flood the pad!”, clock));
events.add(
new LaunchEvent(6, “Start engines!”, clock));
events.add(
new LaunchEvent(0, “Liftoff!”, clock));
clock.start();
for (Runnable e : events)
new Thread(e).start();
}
}
interface TimeMonitor
{
int getTime();
void abortCountDown(); ➞ 26
}
class CountDownClock extends Thread implements TimeMonitor
{
private int t;
continued
LISTING 1-5 (CONTINUED)
public CountDownClock(int start)
{
this.t = start;
}
public void run()
{
boolean aborted = false; ➞ 40
for (; t >= 0; t--)
{
System.out.println(“T minus “ + t);
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
aborted = true; ➞ 50
}
if (Thread.interrupted())
aborted = true; ➞ 53
if (aborted) ➞ 54
{
System.out.println(“Stopping the clock!”);
break;
}
}
}
public int getTime()
{
return t;
}
public synchronized void abortCountDown() ➞ 67
{
Thread[] threads = new Thread[Thread.activeCount()]; ➞ 69
Thread.enumerate(threads); ➞ 70
for(Thread t : threads) ➞ 71
t.interrupt();
}
}
class LaunchEvent implements Runnable
{
private int start;
private String message;
TimeMonitor tm;
public LaunchEvent(int start, String message,
TimeMonitor monitor)
{
this.start = start;
this.message = message;
this.tm = monitor;
}
public void run()
{
boolean eventDone = false;
boolean aborted = false; ➞ 92
while (!eventDone)
{
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
aborted = true; ➞ 101
}
if (tm.getTime() <= start)
{
System.out.println(this.message);
eventDone = true;
System.out.println(“ABORT!!!!”); ➞ 107
tm.abortCountDown(); ➞ 108
}
if (Thread.interrupted())
aborted = true; ➞ 111
if (aborted) ➞ 112
{
System.out.println(“Aborting “ + message);
break;
}
}
}
}
The following paragraphs point out the highlights of this program:
➞ 3 The CountDownApp class itself hasn’t changed. That’s the beauty of
object-oriented programming. Although I changed the implementations
of the CountDownClock and LaunchEvent classes, I didn’t change
the public interfaces for these classes. As a result, no changes are
needed in the CountDownApp class.
➞26 The LaunchEvent class needs a way to notify the CountDownTimer
class that the countdown should be aborted. To do that, I added an
abortCountDown method to the TimeMonitor interface.
➞40 The run method of the CountDownClass uses a boolean variable
named aborted to indicate whether the thread has been interrupted.
This variable is set to true in line 50 if InterruptedException is
caught. It’s also set to true in line 53 if Thread.interrupted()
returns true.
➞54 If the aborted field has been set to true, it means the thread has
been interrupted. So the message Stopping the clock! is
displayed, and a break statement exits the loop. Thus, the thread
is terminated.
➞ 67 The abortCountDown method is synchronized. That’s because any
of the LaunchEvent objects can call it, and there’s no guarantee
that they won’t all try to call it at the same time.
➞ 69 The abortCountDown method starts by creating an array of
Thread objects that’s large enough to hold all the active threads.
The number of active threads is provided by the activeCount
method of the Thread class.
➞ 70 The abortCountDown method then calls the enumerate method of
the Thread class to copy all the active threads into this array. Note
that this method is static, so you don’t need a reference to any particular
thread to use it. (The activeCount method used in line 69 is
static too.)
➞ 71 An enhanced for loop is used to call the interrupt method on all
the active threads. That shuts down everything.
➞ 92 Like the CountDownClock class, the LaunchEvent class uses a
boolean variable to indicate whether the thread has been interrupted.
This thread is set if InterruptedException is caught in
line 101 or if Thread.interrupted() returns true in line 111.
Then, it’s tested in line 112. If it has been set to true, the thread
prints a message indicating that the launch event has been aborted,
and a break statement is used to exit the loop and, therefore, terminate
the thread.
➞101 When the launch event’s start time arrives, the LaunchEvent class
displays the message ABORT! and calls the abortCountDown
method. Thus, the countdown is aborted the first time any launch
event occurs.
When you run this version of the countdown application, here’s what
appears on the console:
T minus 20
T minus 19
T minus 18
T minus 17
T minus 16
Flood the pad!
ABORT!!!!
Stopping the clock!
Aborting Flood the pad!
Aborting Start engines!
Aborting Liftoff!

No comments:

Post a Comment