在这个版本中,正式废除了这样三个方法:stop()、suspend()和resume()。下面我就来介绍一下,为什么它们要被废除:
public class Stop extends Thread {
@Override
public void run() {
try {
while (true)
;
} catch (Throwable e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Thread thread = new Stop();
thread.start();
try {
sleep(1000);
} catch (InterruptedException e) {
}
thread.stop(new Exception("stop")); // note the stack trace
}
}
从上面的代码你应该可以看出两件事情:
1.使用stop来终止一个线程是不讲道理、极其残暴的,不论目标线程在执行任何语句,一律强行终止线程,最终将导致一些残缺的对象和不可预期的问题产生。
2。被终止的线程没有任何异常抛出,你在线程终止后找不到任何被终止时执行的代码行,或者是堆栈信息(上面代码打印的异常仅仅是main线程执行stop语句的异常而已,并非被终止的线程)。
很难想象这样的设计出自一个连指针都被废掉的类型安全的编程语言,对不对?再来看看suspend的使用,有引起死锁的隐患:
public class Suspend extends Thread {
@Override
public void run() {
synchronized (this) {
while (true)
;
}
}
public static void main(String[] args) {
Thread thread = new Suspend();
thread.start();
try {
sleep(1000);
} catch (InterruptedException e) {
}
thread.suspend();
synchronized (thread) { // dead lock
System.out.println("got the lock");
thread.resume();
}
}
}
从上面的代码可以看出,Suspend线程被挂起时,依然占有锁,而当main线程期望去获取该线程来唤醒它时,彻底瘫痪了。由于suspend在这里是无期限限制的,这会变成一个彻彻底底的死锁。
相反,看看这三个方法的改进品和替代品:wait()、notify()和sleep(),它们令线程之间的交互就友好得多:
public class Wait extends Thread {
public void run() {
System.out.println("start");
synchronized (this) { // wait/notify/notifyAll use the same
// synchronization resource
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace(); // notify won't throw exception
}
}
}
public static void main(String[] args) {
Thread thread = new Wait();
thread.start();
try {
sleep(2000);
} catch (InterruptedException e) {
}
synchronized (thread) {
System.out.println("Wait() will release the lock!");
thread.notify();
}
}
}
在wait和notify搭配使用的过程中,注意需要把它们锁定到同一个资源上(例如对象a),即:
1.一个线程中synchronized(a),并在同步块中执行a.wait()
2.另一个线程中synchronized(a),并在同步块中执行a.notify()
再来看一看sleep方法的使用,回答下面两个问题:
1.和wait比较一下,为什么sleep被设计为Thread的一个静态方法(即只让当前线程sleep)?
2.为什么sleep必须要传入一个时间参数,而不允许不限期地sleep?
如果我前面说的你都理解了,你应该能回答这两个问题。
public class Sleep extends Thread {
@Override
public void run() {
System.out.println("start");
synchronized (this) { // sleep() can use (or not) any synchronization resource
try {
/**
* Do you know:
* 1. Why sleep() is designed as a static method comparing with
* wait
* 2. Why sleep() must have a timeout parameter
*/
this.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace(); // notify won't throw exception
}
}
}
public static void main(String[] args) {
Thread thread = new Sleep();
thread.start();
try {
sleep(2000);
} catch (InterruptedException e) {