• 如何正确关闭多线程


    java创建多线程是基础中的基础,继承Thread类、实现Runnable接口和使用Callable和Future创建线程,或者使用线程池创建,这里就不阐述了,那么我们直接进入话题如何正确优雅的关系运行的线程呢?

    在以往项目中,我经常看到一些人写的线程如下

    public class ThreadDemo extends Thread {
     // 建立标记位 控制线程执行
     private volatile boolean flag;
     public boolean isFlag() {
     return flag;
     }
     public void setFlag(boolean flag) {
     this.flag = flag;
     }
     //无参构造方法传入,或者给予一个默认值
     ThreadDemo(boolean flag){
     this.flag = flag;
     }
     @Override
     public void run() {
     while (flag) {
     System.out.println("标记执行线程 running...");
     }
     }
    }
    //测试类
    class runDemo{
     //isInterrupted() true如果这个线程已被中断; false否则。
     //interrupt() 				中断这个线程
     //interrupted() 测试当前线程是否中断,true如果当前线程已被中断; false否则。
     public static void main(String[] args) throws InterruptedException {
     ThreadDemo threadDemo = new ThreadDemo(true);
     threadDemo.start();
     threadDemo.setFlag(false);
     //查看这个方法是否被中断
     System.out.println(threadDemo.isInterrupted()); 
     //不出意外绝b false
     }
    }

    这说明我jdk自带的方法判断竟然返回了flase,但是上这个方法也确实得到了中断,所以这种方法不推荐,真确的写法应该是这个样子的,去除标记位

    public class ThreadDemo extends Thread {
     ThreadDemo(){ }
     @Override
     public void run() {
     while (!isInterrupted()) {//调用原生方法
     System.out.println("标记执行线程 running...");
     }
     }
    }
    //测试类
    class runDemo{
     //isInterrupted() true如果这个线程已被中断; false否则。
     //interrupt() 				中断这个线程
     //interrupted() 测试当前线程是否中断,true如果当前线程已被中断; false否则。
     public static void main(String[] args) throws InterruptedException {
     ThreadDemo threadDemo = new ThreadDemo();
     threadDemo.start();
     TimeUnit.SECONDS.sleep(2);
     //调用中断方法
     threadDemo.interrupt();
     //查看这个方法是否被中断 结果返回true,中断成功
     System.out.println(threadDemo.isInterrupted());
     }
    }

    那么只是简单的这个样子是否认为就完整了呢?答案是不完整的,并且还有缺陷。大家如果仔细观察Thread api 会发现查用的join,sleep等等操作的线程api都会抛出异常java.lang.InterruptedException。下面我们就模拟一下,就是简单的 加了个睡眠,在睡眠过程中断

    public class ThreadDemo extends Thread {
     ThreadDemo(){
     }
    
     @Override
     public void run() {
     while (!isInterrupted()) {
     try {
     System.out.println("标记执行线程 running...");
     //模拟睡眠中,我就执行中断
     TimeUnit.SECONDS.sleep(200);
     } catch (InterruptedException e) {
     System.out.println("打印标记状态isInterrupted="+isInterrupted());
     //打印标记状态isInterrupted=false
     e.printStackTrace();
     }
     }
     }
    }
    //测试类
    class runDemo{
     //isInterrupted() true如果这个线程已被中断; false否则。
     //interrupt() 中断这个线程
     //interrupted() 测试当前线程是否中断,true如果当前线程已被中断; false否则。
     public static void main(String[] args) throws InterruptedException {
     ThreadDemo threadDemo = new ThreadDemo();
     threadDemo.start();
     TimeUnit.SECONDS.sleep(2);
     //调用中断方法
     threadDemo.interrupt();
     //查看这个方法是否被中断
     System.out.println(threadDemo.isInterrupted());
     }
    }

    通过执行会发现抛出了异常 java.lang.InterruptedException: sleep interrupted。所以这个用例还是有问题,当外层调用了中断方法,里面的线程还在运行就会抛出异常并把标记位isInterrupted还原成flase,所以我们需要再次调用中断,合理的让他再次重置标记。改造最后步骤。

    public class ThreadDemo extends Thread {
     ThreadDemo(){}
     @Override
     public void run() {
     while (!isInterrupted()) {
     try {
     //模拟睡眠中,我就执行中断
     System.out.println("标记执行线程 running...");
     TimeUnit.SECONDS.sleep(200);
     } catch (InterruptedException e) {
     System.out.println("打印标记状态isInterrupted="+isInterrupted());
     interrupt();
     System.out.println("打印标记状态isInterrupted="+isInterrupted());
     if (!isInterrupted()) {
     e.printStackTrace();
     }
     }
     }
     }
    }
    //测试类
    class runDemo{
     //isInterrupted() true如果这个线程已被中断; false否则。
     //interrupt() 中断这个线程
     //interrupted() 测试当前线程是否中断,true如果当前线程已被中断; false否则。
     public static void main(String[] args) throws InterruptedException {
     ThreadDemo threadDemo = new ThreadDemo();
     threadDemo.start();
     TimeUnit.SECONDS.sleep(2);
     //调用中断方法
     threadDemo.interrupt();
     //查看这个方法是否被中断
     System.out.println(threadDemo.isInterrupted());
    //运行结果
    // 标记执行线程 running...
    // true 可以看到第一次调用interrupt() 然后咱们输出了一下isInterrupted 是true 但是在下面打印的时候又被重置了false
    // 打印标记状态isInterrupted=false
    // 打印标记状态isInterrupted=true
     }
    }

    以上就是如何正确的使用线程并如何优雅的关闭线程,所以下次大家记得一定要用原生的方法,不要用布尔类型的值去做set和get操作。

  • 相关阅读:
    SimpleXML简单使用
    制作RSS供应源
    DOM方式操作XML
    Referer与图片防盗链
    PAT
    Margarite and the best present
    Petya and Origami
    Margarite and the best present
    Petya and Origami
    A/B
  • 原文地址:https://www.cnblogs.com/liclBlog/p/15349476.html
Copyright © 2020-2023  润新知