• Were not sure what the status of the database is. Did the database get updated? Theres
no way to know. •
Were not going to ever enter that finally block and release the database connection. This may not be a significant resource drain in the client application, but it may be significant
for the database server, especially if we have a database license that allows only a limited number of concurrent connections.
For these reasons, Javasoft deprecated stop
in JDK1.1 and instead recommended that people use a boolean flag inside their implementation of
run . Here, for example, is a simple
schema for subclassing Thread
: public abstract class StoppableThread extends Thread {
... many constructors, weve only included one public StopppableThreadString threadName, Object arg1, OObject
arg2 { superthreadName;
use arg1, arg2, ... to initialize thread state start ;
} private boolean _shouldStopExecuting;
public void setShouldStopExecutingboolean shouldStopExecuting {
_shouldStopExecuting = shouldStopExecuting; }
public boolean getShouldStopExecuting { return _shouldStopExecuting;
} public void run {
while _shouldStopExecuting { performTask ;
} }
protected abstract void performTask ; }
This defines an abstract method, performTask
, and puts it inside a potentially infinite loop. As long as the instances
setShouldStopExecuting method isnt called with a value of
true , the loop will continue, and
performTask will be executed repeatedly.
11.4.3.3 Using Runnable instead of subclassing Thread
The preceding example used a subclass of Thread
to implement the run
method. Another way to accomplish this is to pass in an object to
Thread s constructor. This object needs to
implement the Runnable
interface, which consists of a single method: public void run ;
Generally speaking, people prefer to do this for two reasons. The first is that its slightly cleaner™ it separates what the thread does from the instance that represents the thread. The second
reason is that it preserves flexibility. In Java, a class can extend only one other class. If the class that implements
run extends
Thread , it cannot extend another class in your application.
This can be annoying.
11.4.3.4 Useful methods defined on the Thread class
In addition to providing the ability to start and stop threads, the Thread
class also contains some useful methods that enable you to have a much finer degree of control over individual threads
than wait
notify provide. The most important of these methods are:
public static Thread currentThread ; public static void sleeplong millis;
public static void yield ; public String getName ;
public void setNameString name; public boolean isAlive ;
public int getPriority ; public void setPriorityint newPriority;
The static methods all operate on the currently executing thread. currentThread
returns the instance of
Thread corresponding to the currently executing thread.
sleep causes the
calling thread to become inactive for at least millis
and quite possibly longer. Note that, while asleep, the thread retains any locks it has. And
yield is a milder form of
sleep ™it
causes the thread to become momentarily inactive, but does not guarantee that the thread will remain inactive for any length of time.
One of the more frequent programming errors using threads involves calling sleep
on an instance of
Thread . Java allows you to call static methods on instances of a class and simply
redirects the call to the class object. This can be problematic, as programmers sometimes write lines of code such as:
instanceOfthread.sleep ; which are intended to cause the instance of
Thread to sleep for awhile. But this invokes the
static method sleep
defined on the Thread
class, which will put the calling thread to sleep. setName
and getName
enable you to name a specific thread and find the name of a thread, respectively. These dont actually alter program functionality in any significant way but can
be tremendously useful when debugging. Frequently, the first thing you need to do when something goes wrong is find out which thread is screwing up. If youve given your threads
descriptive names, this becomes much easier. For example, the following line of code can be very convenient:
System.out.printlnThread named + Thread.currentThread.getName + is going
haywire; isAlive
is a method that returns true
if, when it is called, the thread associated with the instance is still alive. There is no guarantee, however, that the thread is still alive when the calling
thread acts on the information. Consider, for example, the following code: if threadInstance.isAlive {
do something }
We could have the following sequence occur in our program: 1. The test is executed and returns
true .
2. The thread associated to threadInstance
expires. 3. The body of the
if statement is executed.
This is usually not what we want to happen. On the other hand, a return value of false
, indicating that the thread has died, is reliable. Threads do not restart once dead, and once
isAlive returns false, it will always return
false .
The final pair of useful methods is getPriority
and setPriority
. A thread with a higher priority usually gets more processor time. Conversely, a thread with a lower priority usually
gets a smaller percentage of the processors time. However, there arent any hard and fast guarantees about this. In all of The Java Language Specification, 2nd Edition edited by Bill Joy
Addison-Wesley, there is exactly one paragraph devoted to thread priorities:
Every thread has a priority. When there is competition for processing resources, threads with higher priority are generally executed in preference to threads with
lower priority. Such preference is not, however, a guarantee that the highest priority thread will always be running, and thread priorities cannot be used to
reliably implement mutual exclusion.
This means that you cant rely on priorities to guarantee program correctness. You can, however, use them as a way to hint to the JVM which threads are more important to you. And doing so is
often useful.
Thread has many other methods that can be useful in certain
situations. And there are other classes that can be used when dealing with sets of threads. The two most useful are
ThreadGroup and
ThreadLocal . Both are defined in
java.lang . Covering the additional methods and classes,
however, is just a little too far outside the scope of this book.
11.5 Deadlock
My boss came into my office a couple of weeks ago. The database metrics arent being recorded again. I think the storage thread is running into a
deadlock.
Why? I asked. Server problems are always deadlocks, he replied.
Technically, he was, of course, incorrect. Servers experience many other types of problems. But there was, nonetheless, a kernel of truth to what he said. Deadlock, a situation in which two or
more threads block each other and force each other to wait forever, is far and away the single most common serious mistake made in writing multithreaded code.
The simplest deadlock scenario involves two threads and two locks. The first thread already has the first lock and is trying to acquire the second lock. The second thread has the second lock and
is trying to acquire the first lock.
For example, this could be caused by two methods with the following structure: public synchronized void method1... {
otherObject.method2 ;} }
public synchronized void method2... { otherObject.method1 ;}
} If there are two methods like this in your code, the following situation can arise: