如何正确关闭多线程

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操作。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值