停止子线程的问题——stop()方法慎用
在项目中由于在线程中需要使用while循环进行轮询操作,当切换网络是需要重新创建该线程,为了避免轮询时间错乱需要判断该线程是否存在,在判断的逻辑中我使用了stop方法,当之前线程存在的时候使用的stop将线程停掉,之后再重新开启一个。
在项目部署的时候就出现了问题,当切换网络再次调用上面的逻辑的时候,轮询是正常的,但是之后的代码调用不到了,经过测试发现是因为stop方法抛出了异常,因此线程根本没有停掉,所以会造成上面的现象
调用线程的stop方法以后抛出下面的异常
java.lang.UnsupportedOperationException
虽然在使用stop方法的时候,知道该方法已经过时,jdk中也不建议使用这个方法来停止线程,但是当时认为使用中已经规避掉该方法的弊端了,也就是项目中的线程没有使用同步锁也没有共享变量所以以为可以大胆的使用,但是还是出错了,看来这个方法真的不能使用。最后判断改成了简单的,如下:
public Thread msgThread;
private static void startHB() {
if(msgThread == null){
msgThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
//UDP接收逻辑修改测试
}
}
});
msgThread.start();
}
}
之前的写法如下,由于调用了stop方法造成了意外的问题。
public Thread msgThread;
private static void startHB() {
if(msgrThread != null){
msgThread.stop();
}
msgThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
//UDP接收逻辑修改测试
}
}
});
msgThread.start();
}
如何停止一个线程呢?
只有一种,run方法结束。
开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束。
当线程处于了冻结状态。就不会读取到标记。那么线程就不会结束。当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除。强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。Thread类提供该方法 interrupt(); 但是会抛出一个InterruptException异常
具体方法有三种:
- 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止
- 使用interrupt()方法中断线程
- 使用stop方法强行终止线程(不推荐使用,可能发生不可预料的结果)
前两种方法都可以实现线程的正常退出,也就是要谈的优雅结束线程;第3种方法相当于电脑断电关机一样,是不安全的方法。
使用标志位:
public class TempThread extends Thread {
public volatile boolean flag = false;
public void run() {
while (!flag){
//do something
}
}
}
定义了一个退出标志flag,当flag为true时,while循环退出,flag的默认值为false.在定义flag时,使用了一个Java关键字volatile,这个关键字的目的是使 flag 同步,也就是说在同一时刻只能由一个线程来修改flag的值。
使用interrupt() 方法来终止线程
线程处于阻塞状态,如使用了sleep,同步锁的wait,socket的receiver,accept等方法时,会使线程处于阻塞状态。当调用线程的interrupt()方法时,系统会抛出一个InterruptedException异常,代码中通过捕获异常,然后break跳出循环状态,使线程正常结束。通常很多人认为只要调用interrupt方法线程就会结束,实际上是错的,一定要先捕获InterruptedException异常之后通过break来跳出循环,才能正常结束run方法。
public class ThreadSafe extends Thread {
public void run() {
while (true){
try{
Thread.sleep(5*1000);阻塞5妙
}catch(InterruptedException e){
e.printStackTrace();
break;//捕获到异常之后,执行break跳出循环。
}
}
}
}
当我们要求终止线程的使用场景是当这个线程处于阻塞状态的时候将其终止,就需要在阻塞状态中该使用线程对象调用interrupt() 方法,这样的使用场景我还没有遇到,如果不是这样的场景都可以使用标志位的方法来终止线程。
参考文章: http://blog.csdn.net/feiduclear_up/article/details/43270375
欢迎关注我的微信公众号,我会把一些生活的感想和投资方面的总结写到公众号,希望你能来和我一起交流技术之外的东西。
张鹤的公众号