另一种能控制线程行为的方法是调用sleep(),这将使线程停止执行一段时间,该时间由
你给定的毫秒数决定。在前面的例子里,要是把对yield( )的调用换成sleep( ),将得
到如下结果:
//: 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 newRuntimeException(e);
}
}
}
public static void
main(String[] args) throws InterruptedException {
for(inti = 0; i < 5; i++)
newSleepingThread().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"
});
}
} ///:~
在你调用sleep()方法的时候,必须把它放在try块中,这是因为sleep( )方法在休眠
时间到期之前有可能被中断。如果某人持有对此线程的引用,并且在此线程上调用了
interrupt( )方法,就会发生这种情况。(如果对线程调用了wait( )或join( )方法,
interrupt( )也会对线程有影响,所以对这些方法的调用也必须放在类似的try块中,
我们将在后面学习这些方法)。通常,如果你想使用interrupt( )来中断一个挂起的线
程,那么挂起的时候最好使用wait()而不是sleep(),这样就不可能在catch子句里
的结束了。这里,我们把异常作为一个RuntimeException重新抛出,这遵循了“除非知
道如何处理,否则不要捕获异常”的原则。
你将会发现程序的输出是确定的,每个线程都在下一个线程开始之前递减计数。这是因为
在每个线程之上都使用了join( )(很快你就会学到),所以main( )在继续执行之前会
等待线程结束。要是你不使用join(),你可能会发现线程可以以任意顺序执行,这说明
sleep( )也不是控制线程执行顺序的方法,它仅仅使线程停止执行一段时间。你得到的唯
一保证是线程将休眠至少 100 毫秒,这个时间段也可能更长,因为在休眠时间到期之后,
线程调度机制也需要时间来恢复线程。
如果你必须要控制线程的执行顺序,你最好是根本不用线程,而是自己编写以特定顺序彼
此控制的协作子程序。