前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何让一个线程“优雅”地退出

如何让一个线程“优雅”地退出

作者头像
CBeann
发布2023-12-25 19:03:04
1840
发布2023-12-25 19:03:04
举报
文章被收录于专栏:CBeann的博客CBeann的博客

stop强制退出(十分不推荐)

记住,线程的终止,并不是简单的调用 stop 命令去。虽然 api 仍然可以调用,但是和其他的线程控制方法如 suspend、resume 一样都是过期了的不建议使用,就拿stop 来说,stop 方法在结束一个线程时并不会保证线程的资源正常释放,因此会导致程序可能出现一些不确定的状态。(参考如何优雅的"中断"一个线程? - 简书

代码语言:javascript
复制
class MyThreadForStop extends Thread {
    @Override
    public void run() {

        while (true) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
            }

            System.out.println(LocalDateTime.now().toString());
        }

    }
}
public static void main(String[] args) {


        MyThreadForStop m1 = new MyThreadForStop();
        m1.start();
        //睡5秒
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
        //关闭当前线程
        m1.stop();


    }

使用标记字段

如下面的demo,所示,定义一个成员变量,通过这个成员变量去控制,每次循环都判断这个变量的状态,从而确定是否要退出。但是这个时候是有一个问题的,比如我在循环中执行一个阻塞的方法,比如阻塞的队列的取操作,如果队列里没有数据,该线程在阻塞状态,我们想停止,但是此时使用标记字段就无能为力了。

代码语言:javascript
复制
class MyThreadForSign extends Thread {

    //volatile标记
    private volatile boolean stop = false;


    public void stopThread() {
        stop = true;
    }

    @Override
    public void run() {

        while (!stop) {
            System.out.println(LocalDateTime.now().toString());
        }

    }
}

MyThreadForSign m1 = new MyThreadForSign();
        m1.start();
        //睡5秒
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
        //关闭当前线程,修改标记位
        m1.stopThread();

interrupt 方法

线程Thread.currentThread().isInterrupted() 默认为false,当你调用interrupt方法后,仅仅是给线程打一个标记,Thread.currentThread().isInterrupted()就会返回true

代码语言:javascript
复制
class MyThreadForInterrupt extends Thread {

    @Override
    public void run() {

        while (!Thread.currentThread().isInterrupted()) {
            System.out.println(LocalDateTime.now().toString());
        }

    }
}

MyThreadForInterrupt m1 = new MyThreadForInterrupt();
        m1.start();
        //睡5秒
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
        //标记中断
        m1.interrupt();
当线程在sleep中,如何优雅的关闭线程

main方法和上面的一样,不贴了,当线程在sleep中,在main方法执行interrupt方法时,会出现异常,此时查看当前线程的中断状态为false(虽然我们调用了interrupt方法,理论上为true,但是sleep的线程不会标记成功),我们只需要捕捉到然后在重新标记,然后就ok了。

代码语言:javascript
复制
class MyThreadForInterrupt extends Thread {


    @Override
    public void run() {

        while (!Thread.currentThread().isInterrupted()) {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                e.printStackTrace();
                //当前线程的中断状态
                System.out.println("Thread.currentThread().isInterrupted():"+Thread.currentThread().isInterrupted());
                //重新设置中断
                this.interrupt();
            } finally {
            }

            System.out.println(LocalDateTime.now().toString());
        }

    }
}
当线程在wait中,如何优雅的关闭线程
代码语言:javascript
复制
class MyThreadForInterrupt extends Thread {

    Lock lock;
    Condition condition;

    public MyThreadForInterrupt(Lock lock) {
        this.lock = lock;
        this.condition = lock.newCondition();
    }


    @Override
    public void run() {


        while (!Thread.currentThread().isInterrupted()){
            System.out.println(LocalDateTime.now().toString());
            lock.lock();
            try {
                //线程在阻塞状态
                condition.await();
            } catch (Exception e) {
                e.printStackTrace();
                //当前线程的中断状态
                System.out.println("Thread.currentThread().isInterrupted():" + Thread.currentThread().isInterrupted());
                this.interrupt();

            } finally {
                lock.unlock();
            }
        }


    }
}


public static void main(String[] args) {

        Lock lock = new ReentrantLock();


        MyThreadForInterrupt m1 = new MyThreadForInterrupt(lock);
        m1.start();
        //睡5秒
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
        //标记中断
        m1.interrupt();


    }
总结

其实都是抛异常,然后捕捉到异常,重新打标记,然后下次循环就能发现标记发生修改,然后就退出了。

参考

线程中断方法interrupt、isInterrupted、interrupted方法_CBeann的博客-CSDN博客

如何优雅的"中断"一个线程? - 简书

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • stop强制退出(十分不推荐)
  • 使用标记字段
  • interrupt 方法
    • 当线程在sleep中,如何优雅的关闭线程
      • 当线程在wait中,如何优雅的关闭线程
        • 总结
        • 参考
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档