前言:学习Thread的suspend、resume、stop方法
简介
首先说明suspend、resume、stop方法已经被废弃了,因为容易造成线程死锁,suspend挂起不会释放锁,其他线程就会继续请求该资源,造成忙等,可以使用wait、notify替代
suspend
使线程挂起,但是不会释放类似锁这样的资源。
resume
使线程恢复,如果之前没有使用suspend暂停线程,则不起作用。
stop
停止当前线程。不会保证释放当前线程占有的资源。
Stop废弃缘由
该方法具有固有的不安全性。用Thread.stop来终止线程将释放它已经锁定的所有监视器(作为沿堆栈向上传播的未检查ThreadDeath异常的一个自然后果)。
如果以前受这些监视器保护的任何对象都处于一种不一致的状态,则损坏的对象将对其他线程可见,这有可能导致任意的行为。
stop的许多使用都应由只修改某些变量以指示目标线程应该停止运行的代码来取代。目标线程应定期检查该变量,并且如果该变量指示它要停止运行,则从其运行方法依次返回。如果目标线程等待很长时间(例如基于一个条件变量),则应使用 interrupt 方法来中断该等待。
当调用Thread.stop()方法时,会发生下面两件事:
即刻抛出ThreadDeath异常,在线程的run()方法内,任何一点都有可能抛出ThreadDeath Error,包括在catch或finally语句中。
会释放该线程所持有的所有的锁,而这种释放是不可控制的,非预期的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public class StopDemo { public static void main(String[] args) { StopThread thread = new StopThread(); thread.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } thread.stop(); while (thread.isAlive()) {
} thread.print(); }
private static class StopThread extends Thread { private int i = 0; private int j = 0;
@Override public void run() { synchronized (this) { ++i; try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } ++j; } } public void print() { System.out.println("i=" + i + " j=" + j); } } }
|
如上代码与结果,正常运行输出i=1,j=1,但是由于在i++之后j++之前就stop,导致数据出现不一致性
取代Thread.stop
大多数stop的使用,应当被替换为简单修改某些变量来指示其目标线程将停止运行的代码。目标线程应当有规律的检查这些变量。并且,如果这些变量指示其将停止运行,目标线程应当以某种有序的方式从它的run方法返回(这正是Java Tutorial一贯建议的方式)。为了确保停止请求的及时传达,变量必须是volatile的(或者变量的访问被同步)。
例如,假设你的applet包含了start、stop和run方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| private Thread blinker;
public void start() { blinker = new Thread(this); blinker.start(); }
public void stop() { blinker.stop(); }
public void run() { Thread thisThread = Thread.currentThread(); while (true) { try { thisThread.sleep(interval); } catch (InterruptedException e){ } repaint(); } }
|
为了避免使用Thread.stop,你可以把applet的stop和run方法替换成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| private volatile Thread blinker;
public void stop() { blinker = null; }
public void run() { Thread thisThread = Thread.currentThread(); while (blinker == thisThread) { try { thisThread.sleep(interval); } catch (InterruptedException e){ } repaint(); } }
|