中断线程
有了上一节[线程的中断],我们就好进行如何[中断线程]了.这绝对不是玩一个文字游戏.是因为"线程的中断"并不能保证"中断线程",所以我要特别地分为两节来说明.
这里说的"中断线程"意思是"停止线程",而为什么不用"停止线程"这个说法呢?
因为线程有一个明确的stop方法,但它是反对使用的,所以请大家记住,在java中以后不要提停止线程这个说法,忘记它!
但是,作为介绍线程知识的我,我仍然要告诉你为什么不用"停止线程"的理由.
[停止线程] 当在一个线程对象上调用stop()方法时,这个线程对象所运行的线程就会立即停止,并抛出特殊的ThreadDeath()异常.这里的"立即"因为太"立即"了,就象一个正在摆弄自己的玩具的孩子,听到大人说快去睡觉去,就放着满地的玩具立即睡觉去了.这样的孩子是不乖的.
假如一个线程正在执行:
synchronized void { x = 3; y = 4;}由于方法是同步的,多个线程访问时总能保证x,y被同时赋值,而如果一个线程正在执行到x = 3;时,被调用了 stop()方法,即使在同步块中,它也干脆地stop了,这样就产生了不完整的残废数据.而多线程编程中最最基础的条件要保证数据的完整性,所以请忘记线程的stop方法,以后我们再也不要说"停止线程"了.
如何才能"结束"一个线程?[中断线程] 结束一个线程,我们要分析线程的运行情况.也就是线程正在干什么.如果那个孩子什么事也没干,那就让他立即去睡觉.而如果那个孩子正在摆弄他的玩具,我们就要让它把玩具收拾好再睡觉.
所以一个线程从运行到真正的结束,应该有三个阶段:
1.正常运行. 2.处理结束前的工作,也就是准备结束. 3.结束退出.
在我的JDBC专栏中我N次提醒在一个SQL逻辑结束后,无论如何要保证关闭Connnection那就是在finally从句中进行.同样,线程在结束前的工作应该在finally中来保证线程退出前一定执行:
try{ 正在逻辑 }catch(){} finally{ 清理工作 }
那么如何让一个线程结束呢?既然不能调用stop,可用的只的interrupt()方法.但interrupt()方法只是改变了线程的运行状态,如何让它退出运行?
对于一般逻辑,只要线程状态为已经中断,我们就可以让它退出,所以这样的语句可以保证线程在中断后就能结束运行:
while(!isInterrupted()){ 正常逻辑 } 这样如果这个线程被调用interrupt()方法,isInterrupted()为true,就会退出运行.但是如果线程正在执行wait,sleep,join方法,你调用interrupt()方法,这个逻辑就不完全了.
如果一个有经验的程序员来处理线程的运行的结束:
public void run(){ try{ while(!isInterrupted()){ 正常工作 } } catch(Exception e){ return; } finally{ 清理工作 } }我们看到,如果线程执行一般逻辑在调用innterrupt后.isInterrupted()为true,退出循环后执行清理工作后结束,即使线程正在wait,sleep,join,也会抛出异常执行清理工作后退出.这看起来非常好,线程完全按最我们设定的思路在工作.但是,并不是每个程序员都有这种认识,如果他聪明的自己处理异常会如何?事实上很多或大多数程序员会这样处理:
public void run(){ while(!isInterrupted()){ try{ 正常工作 }catch(Exception e){ //nothing } finally{ } } }
想一想,如果一个正在sleep的线程,在调用interrupt后,会如何? wait方法检查到isInterrupted()为true,抛出异常,而你又没有处理.而一个抛出了InterruptedException的线程的状态马上就会被置为非中断状态,如果catch语句没有处理异常,则下一次循环中isInterrupted()为false,线程会继续执行,可能你N次抛出异常,也无法让线程停止.
那么如何能确保线程真正停止? 在线程同步的时候我们有一个叫"二次惰性检测"(double check),能在提高效率的基础上又确保线程真正中同步控制中. 那么我把线程正确退出的方法称为"双重安全退出",即不以isInterrupted()为循环条件.而以一个标记作为循环条件:
class MyThread extend Thread{ private boolean isInterrupted = false;//这一句以后要修改
public void interrupt(){ isInterrupted = true; super.interrupt(); } public void run(){ while(!isInterrupted){ try{ 正常工作 }catch(Exception e){ //nothing } finally{ } } }}
试试这段程序,可以正确工作吗?对于这段程序仍然还有很多可说的地方,先到这里吧.