如何正确停止线程

原理:new一个Thread对象,如:Thread thread=new Thread(Runnable接口的实现类);然后调用thread.interrupt()方法

使用thread.interrupt(),只是发出中段信号,线程停不停止并不由自己决定,而是由被停止的线程决定,不是强制停止线程。

  • 普通情况下停止线程(run内没有sleep或者wait方法),还需要调用!Thread.currentThread().isInterrupted()表示被停止的线程配合接收到中断信号,同时停止线程
/**
 * run内没有sleep或者wait方法时,停止线程
 */
public class RightWayStopThreadWithoutSleep implements  Runnable{
    @Override
    public void run() {
        int num=0;
        while(!Thread.currentThread().isInterrupted()&&num<=Integer.MAX_VALUE/2){
            if(num%10000==0){
                System.out.println(num+"是一万的倍数");
            }
            num++;
        }
        System.out.println("任务运行结束了");
    }
    public static void main(String[] args) {
        Thread thread=new Thread(new RightWayStopThreadWithoutSleep());
        thread.start();
        try {
            //线程运行一秒钟之后给他截断(进入阻塞?)
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
    }
}
  • 阻塞情况下停止线程(即带sleep方法中断线程)
/**
 * 带有sleep方法中断线程
 */
public class RightWayStopThreadWithSleep {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable=()->{
            int num=0;
            try {
                while (num <= 300 && !Thread.currentThread().isInterrupted()) {
                    if (num % 100 == 0) {
                        System.out.println(num + "是100的倍数");
                    }
                    num++;
                }
                Thread.sleep(10000);//让线程阻塞10秒
            }catch (InterruptedException e  ){
                e.printStackTrace();
            }
        };
        Thread thread=new Thread(runnable);
        thread.start();
        thread.sleep(9000);//我们在10s处无法中断,因为10s时人家已经没有停止,也就无法中断
        thread.interrupt();
    }
}

每次迭代(循环)都阻塞情况下停止线程

/**
 * 在使用过程中,每次循环都会调用sleep或wait等方法,那么就不需要每次迭代都要检查是否已经中断
 */
public class RightWayStopThreadEveryLoop {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable=()->{
            int num=0;
            try {
                while (num <= 10000) {
                    if (num % 100 == 0) {
                        System.out.println(num + "是100的倍数");
                    }
                    num++;
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(100);//让线程阻塞0.01秒,所以出现打印的过程比较慢
                    //这个过程线程可能就会收到这个通知,将线程停止
                }
            }catch (InterruptedException e  ){
                e.printStackTrace();
            }
        };
        Thread thread=new Thread(runnable);
        thread.start();
        thread.sleep(5000);//让线程运行到第五秒时停止
        System.out.println(Thread.currentThread().getName());
        thread.interrupt();//发送停止消息,
    }
}

这里要注意一种情况:就是while里面方法try/catch的问题,一旦响应中断,会将interrupt标记位清除

/**
 * 如果while里面放try-catch,会导致中断失效
 */
public class CantInterrupt {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable=()->{
            int num=0;
            while(num<=10000){
                if(num%100==0){
                    System.out.println(num+"是100的倍数");
                }
                num++;
                try {
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread thread=new Thread(runnable);
        thread.start();
        Thread.sleep(500);//主动发送信号
        System.out.println(Thread.currentThread().getName());
        thread.interrupt();
    }
}

最佳停止线程的二种方法:

  • 优先选择:传递中断,这种方法出现的情况是若在run方法里面有一个方法不是我们写的而是由别的人写的,正因为方法是别人写的,方法里面的具体细节我们并不知道,里面的对异常的处理我们也就不知道,也就不能响应中断了,即使添加检验也无法获取到中断信息。注意,run方法无法抛出受检异常,只能用try/catch

/**
 * 最佳实践:catch住了InterruptedException之后优先选择:在方法签名中抛出异常
 * 那么在run()就会强制try/catch
 */
public class RightWayStopThreadInProduct implements Runnable{
    @Override
    public void run() {
        while (true){
            try {
                //这里只提示只能用try/catch
                System.out.println("gogo");
                throwInMethod();
                System.out.println("打印日志");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    private void throwInMethod() throws InterruptedException {
            Thread.sleep(2000);
    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(new RightWayStopThreadInProduct());
        thread.start();
        Thread.sleep(1000);
        thread.interrupt();
    }
}
  • 不想或无法传递:恢复中断,在catch字句中调用Thread.currentThread().isInterrupted()
      来恢复设置中断状态,以便在后续的执行中,依然能够检查到刚才发生了中断
/**
 * 最佳实践2:在catch字句中调用Thread.currentThread().isInterrupted()
 * 来恢复设置中断状态,以便在后续的执行中,依然能够检查到刚才发生了中断
 */
public class RightWayStopThreadInProduct2 implements Runnable{
    @Override
    public void run() {
        while (true){
                //如果线程已经被中断,这时就可以检测中断信息了
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("Interruped,程序运行结束");
                break;
            }
             reInterrupe();
        }
    }
    private void reInterrupe()  {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            //重新设置中断
            Thread.currentThread().interrupt();
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(new RightWayStopThreadInProduct2());
        thread.start();
        Thread.sleep(1000);
        thread.interrupt();
    }
}

最后补充一点关于异常的信息:Error和RuntimeException都是非检查异常,也即是编译器无法预测的,而其他的异常都是受检查异常

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值