If you
replace the call to yield( ) in the above example with a call to sleep( ),
you get the following: Feedback
//: c13:SleepingThread.java
// Calling sleep() to wait for awhile.
import com.bruceeckel.simpletest.*;
public class SleepingThread extends Thread {
private static Test monitor = new Test();
private int countDown = 5;
private static int threadCount = 0;
public SleepingThread() {
super("" + ++threadCount);
start();
}
public String toString() {
return "#" + getName() + ": " + countDown;
}
public void run() {
while(true) {
System.out.println(this);
if(--countDown == 0) return;
try {
sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
716
Thinking in Java
www.BruceEckel.com
public static void
main(String[] args) throws InterruptedException {
for(int i = 0; i < 5; i++)
new SleepingThread().join();
monitor.expect(new String[] {
"#1: 5",
"#1: 4",
"#1: 3",
"#1: 2",
"#1: 1",
"#2: 5",
"#2: 4",
"#2: 3",
"#2: 2",
"#2: 1",
"#3: 5",
"#3: 4",
"#3: 3",
"#3: 2",
"#3: 1",
"#4: 5",
"#4: 4",
"#4: 3",
"#4: 2",
"#4: 1",
"#5: 5",
"#5: 4",
"#5: 3",
"#5: 2",
"#5: 1"
});
}
} ///:~
When you call sleep( ), it must be placed inside a try block because it’s
possible for sleep( ) to be interrupted before it times out. This happens if
someone else has a reference to the thread and they call interrupt( ) on
the thread (interrupt( ) also affects the thread if wait( ) or join( ) has been called for it, so those calls must be in a similar try block—you’ll
learn about those methods later). Usually, if you’re going to break out of a
suspended thread using interrupt( ) you will use wait( ) rather than
sleep( ), so ending up inside of the catch clause is unlikely. Here, we
Chapter 13: Concurrency
717
follow the maxim “don’t catch an exception unless you know what to do
with it” by re-throwing it as a RuntimeException. Feedback
You’ll notice that the output is deterministic – each thread counts down
before the next one starts. This is because join( ) (which you’ll learn
about shortly) is used on each thread, so that main( ) waits for the thread
to complete before continuing. If you did not use join( ), you’d see that
the threads tend to run in any order, which means that sleep( ) is also
not a way for you to control the order of thread execution. It just stops the
execution of the thread for awhile. The only guarantee that you have is
that the thread will sleep at least 100 milliseconds, but it may take longer
before the thread resumes execution because the thread scheduler still
has to get back to it after the sleep interval expires. Feedback
If you must control the order of execution of threads, your best bet is not
to use threads at all but instead to write your own cooperative routines
which hand control to each other in a specified order. Feedback
Priority
The priority of a thread tells the scheduler how important this thread is.
Although the order that the CPU attends to an existing set of threads is
indeterminate, if there are a number of threads blocked and waiting to be
run, the scheduler will lean towards the one with the highest priority first.
However, this doesn’t mean that threads with lower priority don’t get run
(that is, you can’t get deadlocked because of priorities). Lower priority
threads just tend to run less often. Feedback
Here’s SimpleThread.java modified so that the priority levels are
demonstrated. The priorities are adjusting using Thread’s
setPriority( ) method.
//: c13:SimplePriorities.java
// Shows the use of thread priorities.
import com.bruceeckel.simpletest.*;
public class SimplePriorities extends Thread {
private static Test monitor = new Test();
private int countDown = 5;
private volatile double d = 0; // No optimization
public SimplePriorities(int priority) {
718
Thinking in Java
www.BruceEckel.com
setPriority(priority);
start();
}
public String toString() {
return super.toString() + ": " + countDown;
}
public void run() {
while(true) {
// An expensive, interruptable operation:
for(int i = 1; i < 100000; i++)
d = d + (Math.PI + Math.E) / (double)i;
System.out.println(this);
if(--countDown == 0) return;
}
}
public static void main(String[] args) {
new SimplePriorities(Thread.MAX_PRIORITY);
for(int i = 0; i < 5; i++)
new SimplePriorities(Thread.MIN_PRIORITY);
monitor.expect(new String[] {
"Thread[Thread-1,10,main]: 5",
"Thread[Thread-1,10,main]: 4",
"Thread[Thread-1,10,main]: 3",
"Thread[Thread-1,10,main]: 2",
"Thread[Thread-1,10,main]: 1",
"Thread[Thread-2,1,main]: 5",
"Thread[Thread-2,1,main]: 4",
"Thread[Thread-2,1,main]: 3",
"Thread[Thread-2,1,main]: 2",
"Thread[Thread-2,1,main]: 1",
"Thread[Thread-3,1,main]: 5",
"Thread[Thread-4,1,main]: 5",
"Thread[Thread-5,1,main]: 5",
"Thread[Thread-6,1,main]: 5",
"Thread[Thread-3,1,main]: 4",
"Thread[Thread-4,1,main]: 4",
"Thread[Thread-5,1,main]: 4",
"Thread[Thread-6,1,main]: 4",
"Thread[Thread-3,1,main]: 3",
|