正常的情况下,业务系统都不会去中断它的线程,但是由于一些特殊情况的发生,线程已经不能正常结束了,并且此类线程已经影响到业务系统提供服务的能力,如果系统设计的健壮,便会通过监控线程去主动的中断此类线程。但是如果随意的去中断线程,又是非常危险的,因为线程内部会占用资源和改变变量的内容等,最好的办法是向线程发送中断信号,由线程自己去中断自己。
源码地址: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异常;