《六》实际应用——如何优雅的关闭线程

Java并发编程系列文章
《一》多线程基础——Java线程与进程的基本概念
《二》多线程基础——Java线程入门类和接口
《三》多线程基础——Java线程组和线程优先级
《四》多线程基础——Java线程生命周期及转换
《五》多线程基础——Java线程间的通信(互斥与协作)
《六》实际应用——如何优雅的关闭线程
《七》实际应用——生产者与消费者模型

  并发编程(多线程)一直以来都是程序员头疼的难题。曾经听别人总结过并发编程的第一原则,那就是不要写并发程序,哈哈哈。后来发现,这样能够显著提高程序响应和吞吐量的利器,哪还能忍得住不会用呢?
  整理出《Java并发编程系列文章》,共计7篇,与君共勉。



1、开关的方式关闭线程

  在实际开发中,什么时候会需要主动关闭线程呢?举个例子,当你用多线程读取Excel中的数据存入数据库,要处理的某个Excel中有100万条数据时,假设你代码中设置10万条数据启动一个线程处理,最多同时启动5个线程。如果启动的线程在处理业务逻辑时报错了,你想立即关闭并重新启一个。废话不多说,直接贴Demo代码:

public class Work extends Thread{
    private volatile boolean start = true; //设置开关

    @Override
    public void run() {
        while (start){
            System.out.println("业务逻辑正在执行......"); //业务逻辑
        }
    }

    public void shutdown(){
        this.start = false;
    }
}
    public static void main(String[] args) throws InterruptedException {
        Work work = new Work();
        work.start();

        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }

        work.shutdown(); //主动关闭线程

    }

2、打断的方式关闭线程

2.1、线程处于WAITING、TIMED_WAITING

  在实际开发中,当你的线程调用了wait()、或者sleep()等方法,进入等待或超时等待,而你又想主动结束这个线程时,就可以适用这种情况。废话不多说,直接贴Demo代码:

public class Work extends Thread{
    @Override
    public void run() {
        while (true){
            try {
                System.out.println("业务逻辑正在执行......"); //业务逻辑
                Thread.sleep(3000);
            }catch (InterruptedException e){
                System.out.println("正在退出线程执行......");
                break; //return
            }
        }
    }
}
    public static void main(String[] args) throws InterruptedException {
        Work work = new Work();
        work.start();

        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }

        work.interrupt();
    }

2.2、线程不处于WAITING、TIMED_WAITING

  在实际开发中,当你的线程不处于等待或超时等待,而你又想主动结束这个线程时,就可以适用这种情况。废话不多说,直接贴Demo代码:

public class Work extends Thread{
    @Override
    public void run() {
        while (true){
            if(Thread.interrupted()){
                System.out.println("正在退出线程执行......");
                break; //return
            }
            System.out.println("业务逻辑正在执行......"); //业务逻辑
        }
    }
}
    public static void main(String[] args) throws InterruptedException {
        Work work = new Work();
        work.start();

        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }

        work.interrupt();
    }

3、自定义封装Thread,暴力关闭线程

  在实际开发中,当你的线程调用第三方接口阻塞、读一个网络资源超时或者处理业务逻辑阻塞了,你即便修改开关的值或者打断它,依然无法使正处于阻塞中的线程感知到时。而你却想给它设置一个超时时间,超过这个时间就自动关闭。废话不多说,直接贴Demo代码:

public class MyThread {
    private Thread executeThread;
    private boolean finished = false;

    public void execute(Runnable task){
        executeThread = new Thread(){
            @Override
            public void run() {
                Thread runner = new Thread(task);
                runner.setDaemon(true);
                runner.start();
                try {
                    runner.join();
                    finished = true;
                } catch (InterruptedException e) {
                    //e.printStackTrace();
                    //关闭线程
                }
            }
        };
        executeThread.start();
    }

    public void shutdown(long mills){
        long currentTime = System.currentTimeMillis();
        while (!finished){
            //任务还在执行中,判断是否超时
            if((System.currentTimeMillis() - currentTime) >= mills){
                System.out.println("任务超时,需要结束。");
                executeThread.interrupt();
                break;
            }

            //任务还在执行中,未超时。让executeThread休眠0.001秒,再判断finished
            try {
                executeThread.sleep(1);
            }catch (InterruptedException e){
                System.out.println("执行线程被打断");
                break;
            }
        }
        finished = false;
    }
}
    public static void main(String[] args){
        MyThread thread = new MyThread();
        long start = System.currentTimeMillis();
        thread.execute(()->{
            while (true){

            }
        });
        thread.shutdown(10000);
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

  自定义封装了一个MyThread类,当我们调用它的execute()方法时,它会启动一个执行线程,让执行线程将传入的任务线程初始化,并设置成执行线程的守护线程。当启动并join任务线程后,执行线程将阻塞,等任务线程执行完,执行线程才会退出。
  我们可以调用它的shutdown(long)方法,如果任务线程正在执行且已经超时,shutdown()方法会打断执行线程,因为任务线程执行线程的守护线程,所以当执行线程被终止,那么任务线程也会终止。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值