正常的情况下,业务系统都不会去中断它的线程,但是由于一些特殊情况的发生,线程已经不能正常结束了,并且此类线程已经影响到业务系统提供服务的能力,如果系统设计的健壮,便会通过监控线程去主动的中断此类线程。但是如果随意的去中断线程,又是非常危险的,因为线程内部会占用资源和改变变量的内容等,最好的办法是向线程发送中断信号,由线程自己去中断自己。
源码地址:https://github.com/mantuliu/javaAdvance
首先,我们先分析一下源代码用demo来看一下,stop()和suspend()方法的问题:
public final void stop() {
stop(new ThreadDeath());
} public final synchronized void stop(Throwable obj) {//注意这里用了同步标识
if (obj == null)
throw new NullPointerException(); SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if ((this != Thread.currentThread()) ||
(!(obj instanceof ThreadDeath))) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
// A zero status value corresponds to "NEW", it can't change to
// not-NEW because we hold the lock.
if (threadStatus != 0) {
resume(); // Wake up thread if it was suspended; no-op otherwise 如果线程是suspended的,还有个唤醒操作,有可能会发生死锁
} // The VM can handle all thread states
stop0(obj);//停止线程,未恢复已用的变量状态
}
看了以上代码,有3点推论:1.stop()线程因为是从外部干掉的,对于业务上使用的变量没有将其状态还原;2.stop()方法没有抛出异常,用户没有得到警告3.如果对线程对象本身加了锁并且一直没有释放,例如调用suspend()方法,那么此线程通过stop()方法不能被停止;
demo Class Lesson6ThreadStopLock 已经展示了结论1和2;
demo Class Lesson6ThreadStopDeadLock展示了结论3,并证明了suspend方法因为不释放与线程相关的任何锁资源,容易造成死锁。
既然我们不能使用stop()方法去中断线程,我们应该使用什么方法呢,在本文的开头我们提到了向目标线程发送中断信号,由它自行中断,这个中断指令就是interrupt()方法,在和线程相关的很多方法及关键字中,有一些是不响应中断的,例如:Lock类的lock()方法、Condition类的awaitUninterruptibly()方法、synchronized关键字等。
demo Class Lesson6InterruptSync 展示了synchronized不响应中断;
demo Class Lesson6InterruptLock 展示了lockInterruptibly()方法可以响应中断,并抛出java.lang.InterruptedException异常;