如何优雅的中断线程

1. 前言

今天的主题是:如何优雅的中断线程。 会列举出几种中断线程的办法,同时也会扩展一定的知识。废话不多说,我们开始吧!!!

2. 前置知识

2.1 interrupt API

此API号称是可以中断线程。但是其实这种想法有一定的歧义。不应该说是可以中断线程,而是对线程进行标记。通过判断标记来中断线程

2.1.1 基本的API

  • public void interrupt 此方法是一个实例方法,用来标记线程
  • public boolean isInterrupted 此方法是一个实例方法,用来判断线程是否被标记
  • public static boolean interrupted 此方法是一个静态方法,返回判断是否被标记,同时清空标记

2.1.2 实例

public class Thread_04_interrupt_study {
    public static void main(String[] args) throws InterruptedException {
        testInterrupt02();
    }

    public static void testInterrupt02() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (;;) {
                if (Thread.interrupted()) {
                    System.out.println("此线程被标记了,并且清除了标记");
                    break;
                }
                System.out.println("这是一个子线程:" + Thread.currentThread().getName());
            }
        });

        t1.start();

        Thread.sleep(1000);

        t1.interrupt();

        Thread.sleep(1000);

        System.out.println("是否还有状态:" + t1.isInterrupted());
    }

    public static void testInterrupt01() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (;;) {
                // 判断线程是否被标记中断
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("此进程被标记了");
                    break;
                }
                System.out.println("这是一个子进程:" + Thread.currentThread().getName());
            }
        });

        t1.start();

        Thread.sleep(1000);

        // 此时对线程进行标记
        t1.interrupt();
    }
}

2.2 当interrupt遇到join/ sleep/ wait

  1. interrupt 遇到sleep/ wait等得时候,程序会报错。所以我们可以捕获异常,在异常中做别的处理
  2. 换言之,当interrupt 遇到 sleep等 会打断原来要做的事情。 开始执行异常
public class Thread_05_interrupt_sleep_wait {

    public static final Object o = new Object();

    public static void main(String[] args) throws InterruptedException {
        test02();
    }

    public static void test02() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                synchronized (o) {
                    try {
                        o.wait();
                    } catch (InterruptedException e) {
                        System.out.println("遇到异常了  重新执行");
                    }
                }
            }
        });

        t1.start();
        Thread.sleep(1000);
        t1.interrupt();
    }

    public static void test01() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("sleep 被唤醒可以继续执行了");
                }
                if (Thread.interrupted()) {
                    System.out.println("我是被标记的线程:" + Thread
                            .currentThread().getName());
                }
            }
        });

        t1.start();

        Thread.sleep(1000);

        t1.interrupt();
    }
}

2.3 当interrupt 遇到synchronized/ lock

结论:interrupt 不会中断竞争锁的线程。 但是lockInterruptibly 除外

public class Thread_06_interrupt_sync {

    private static final Object o = new Object();

    public static void main(String[] args) throws InterruptedException {
        test01();
    }

    public static void test01() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            synchronized (o) {
                try {
                    System.out.println("wo shi t1");
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        t1.start();
        Thread.sleep(1000);

        Thread t2 = new Thread(() -> {
            synchronized (o) {

            }
            System.out.println("wo shi t2");
        });

        t2.start();

        Thread.sleep(1000);

        t2.interrupt();
    }
}

3. 中断线程的几种方式

3.1 stop

我们可以使用API【stop】进行中断。但是此API已经被废弃了。同样是不推荐使用。因为过于粗暴,无法保证数据的一致性。

    public static void testStop01() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                    System.out.println("这是一个线程" + Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        t1.start();

        Thread.sleep(2000);

        t1.stop();
    }

3.2 suspend/ resume

通过暂停以及启动 可以中断线程。但是也是因为粗暴,而且无法准备的判断。所以其实不支持使用它来中断线程的

    public static void testStop02() throws InterruptedException {
        Thread t1 = new Thread(() -> {
           while (true) {
               System.out.println("这是一个线程:" + Thread.currentThread().getName());
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }
        });

        t1.start();

        Thread.sleep(2000);

        // 表示暂停
        t1.suspend();
        Thread.sleep(2000);
        // 表示开始
        t1.resume();
    }

3.3 volatile

可以通过volatile 轻量锁来实现线程中断。其实就是一个特殊的flag。 控制起来相对比较灵活,值得推荐

    public static void testStop03() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            Integer count = 0;
            while (running) {
                if (count >= 10) {
                    running = false;
                }
                try {
                    Thread.sleep(100);
                    count ++;
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("同步 执行结束");
        });

        t1.start();

        Thread.sleep(2000);
    }

3.4 interrupt

我们可以通过API【interrupt】进行线程标记。通过判断线程是否被标记来执行别的逻辑。这种方式相对来说会更加优雅一点。 但是其实上述方式3.3 也相对比较优雅

    public static void testStop04() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (!Thread.interrupted()) {
            }
            System.out.println(
                    "执行当前线程" + Thread.currentThread().getName()
            );
        });
        t1.start();

        Thread.sleep(2000);

        t1.interrupt();
    }

4. 总结

上述是几种中断线程的方式。不管是理由还是代码都列举出来了。源码参照这个地方. 如果大家有不同的意见,欢迎评论区留言。让我们一起成长。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值