java 多线程编程系列之5----如何优雅的结束线程

        线程的结束方式一stop:

        stop()会释放所有的锁,并且不会做善后工作,会导致其他线程抢到锁,然后读取到中间数据导致数据不一致;所以stop方法废弃了;

public class TestThread {

    @SneakyThrows
    public static void main(String[] s){

        Thread t1 = new Thread(()->{
            while (true){
                try {
                    System.out.println("go on ...");
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        TimeUnit.SECONDS.sleep(5);
        t1.stop();
    }
}

        线程的暂停/继续:

        暂停的时候是不会释放当前线程所拥有的锁的,假如你没有继续启动resume的话就会导致死锁,所以这两个方法suspend()和resume()废弃了,最好别轻易使用。

public class TestThread {

    @SneakyThrows
    public static void main(String[] s){

        Thread t1 = new Thread(()->{
            while (true){
                try {
                    System.out.println("go on ...");
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        TimeUnit.SECONDS.sleep(5);
        t1.suspend();//暂停
        TimeUnit.SECONDS.sleep(3);
        t1.resume();//继续
    }
}

        利用volatile控制线程:

public class TestThread {

    private static volatile boolean runFlag = true;
    @SneakyThrows
    public static void main(String[] s){

        Thread t = new Thread(()->{
           long i = 0L;
           while (runFlag){
               i++;
           }
           System.out.println("run end and i="+i);
           //第一次运行 输出:run end and i=3574874025
           //第二次运行 输出:run end and i=3587827843 
        });

        t.start();
        TimeUnit.SECONDS.sleep(1);
        runFlag = false;
    }
}

        上面的代码是用volatile修饰的变量来判断是否结束线程,是比较优雅的结束线程,但你很难精确的控制线程运行了多少次才结束,所以你只要不依赖线程的中间状态来判断释放结束,volatile还是比较可以的;

        利用interrup来结束线程:

public class TestThread {

    @SneakyThrows
    public static void main(String[] s){

        Thread t = new Thread(()->{
           while (!Thread.interrupted()){
           }
           System.out.println("t end !");
        });
        t.start();
        TimeUnit.SECONDS.sleep(1);
        t.interrupt();

    }
}

        Interrupt设置标志位来打断线程跟volatile类似;interrupt更优雅一点,因为在线程sleep,wait,join的时候interrupt可以捕获异常来做进一步处理(比如做中断线程的处理),但是volatile是判断不了的只能等待、死等,不能跳到下一次循环去读取running变量的值;

        利用interrupt()和isInterrupted优雅的结束线程

public class TestThread {

    @SneakyThrows
    public static void main(String[] s){

         Thread t = new Thread(()->{
             for (;;){
                if (Thread.currentThread().isInterrupted()){
                    System.out.println("Thread is interrupted!");
                    System.out.println(Thread.currentThread().isInterrupted());
                    break;
                }
             }
         });
         t.start();
         TimeUnit.SECONDS.sleep(2);
         t.interrupt();

    }
}

        总结结束线程的方法:

1. 自然结束(能自然结束尽量自然结束)

2. stop() suspend() resume() 等方式结束

3. 通过判断volatile标志来结束

         a. 不适合某些场景(比如volatile变量还没同步的时候线程就做了阻塞,则没有办法循环回去)

        b. 打断时间不精准,比如一个阻塞集合,容量为1000的时候希望结束线程不要再添加,但是由于volatile同步线程标志位的时间控制的不是很精准,有可能线程还要继续跑一会儿才会停止。

4. 利用interrupt() 和 isInterrupted() 来优雅的控制线程的结束。

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值