线程的“结束”

【一道概率很高的面试题】:

  • 如何优雅的结束一个线程?
    上传一个大文件,正在处理费时的计算,如何优雅的结束这个线程呢?

【stop方法】:

【为何不建议使用stop呢?】:
因为很容易产生数据不一致的问题;
stop方法不管你线程处于什么状态,如果持有很多把锁,它会二话不说释放所有的锁,并且不会做善后的工作。原先的锁如果是为了数据的一致性,那么使用stop有可能就会打破数据的一致性。

 public class T01_Stop {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (true) {
                System.out.println("go on");
                SleepHelper.sleepSeconds(1);
            }
        });

        t.start();

        SleepHelper.sleepSeconds(5);

        t.stop();  //不建议大家使用。
    }
}

在这里插入图片描述

【 suspend_resume 】:

【这两个方法被废掉的原因】:
原因和stop非常的类似 , 万一暂停的瞬间持有一把锁 , 这一把锁是不会被释放的,如果你忘记了恢复,那么就缔造出了一把《永恒的锁》。所以也是会产生数据不一致的问题的。

public class T02_Suspend_Resume {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (true) {
                System.out.println("go on");
                SleepHelper.sleepSeconds(1);
            }
        });

        t.start();

        SleepHelper.sleepSeconds(5);

        t.suspend();  //暂停;
        SleepHelper.sleepSeconds(3);
        t.resume();  //恢复执行。
    }
}

【volatile结束线程】:

【不太适合的情况】:
循环中有个数统计的计数器。
循环中有wait、recv、accept等方法,wait会阻塞住,不能进行下一次循环,也无法结束。
【适合的情况】:
不太依赖中间的状态——如上传数据,多上传一些 / 少上传一些 都不影响的这种情况。

public class T03_VolatileFlag {

    private static volatile boolean running = true;

    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            long i = 0L;
            while (running) {
                //wait recv accept
                i++;
            }

            System.out.println("end and i = " + i); //4168806262 4163032200
        });

        t.start();

        SleepHelper.sleepSeconds(1);

        running = false;
    }
}

【interrupt结束线程】:

//interrupt比volatile更加优雅一些 , 因为如果是volatile的话 , 中间有一些wait / sleep 的话 , 你是停不了的 , 无法跳到下一次循环。但如果是interrupt的话,你只要在sleep / wait 里面处理 InterruptedException 也可以正确的结束这个线程。
【仍有缺点】:
10个元素的容器 , 精确到第5个 , 这个也是无法达到的!!!
【这种情况如何正常结束呢?】:
必须生产者Thread和外面打断它的Thread , 两者配合才可以。
【其他方法】:
内部线程进行定时的检查 , 每隔多长时间检查一次标志位 , 每经过一次循环检查一次标志位。

/**
 * interrupt是设定标志位
 */
public class T04_Interrupt_and_NormalThread {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (!Thread.interrupted()) {   //只要标记位没被设置,我就一直循环~ ~ ~
                //sleep wait
            }

            System.out.println("t1 end!");
        });

        t.start();

        SleepHelper.sleepSeconds(3);

        t.interrupt();
    }
}
public class T05_InterruptAndPark {
    public static void main(String[] args) {

        Thread t = new Thread(() -> {
            System.out.println("1");
            LockSupport.park();
            System.out.println("2");
        });

        t.start();

        SleepHelper.sleepSeconds(2);

        t.interrupt();
    }
}

【阶段总结】:

【volatile 和 interrupt】:
总之,你不依赖于中间精确的次数和精确的时间的话 , 它俩都行。

【结束线程的方法】:

  1. 自然结束(能自然结束就尽量自然结束)
  2. stop() suspend() resume()
  3. volatile标志
    1. 不适合某些场景(比如还没有同步的时候,线程做了阻塞操作,没有办法循环回去)
    2. 打断时间也不是特别精确,比如一个阻塞容器,容量为5的时候结束生产者,
      但是,由于volatile同步线程标志位的时间控制不是很精确,有可能生产者还继续生产一段儿时间
  4. interrupt() and isInterrupted(比较优雅)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值