美文网首页并发编程
4.1、线程中断

4.1、线程中断

作者: liyc712 | 来源:发表于2020-09-01 11:49 被阅读0次

    线程的中断操作

    一、Thread.interrupt方法(推荐使用)

    /**
     * 使用interrupt中断线程
     */
    public class InterruptDemo implements  Runnable {
        @Override
        public void run() {
            // 判断是否被中断了
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName());
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread thread = new Thread(new InterruptDemo());
            thread.start();
            Thread.sleep(1000L);
            thread.interrupt();
        }
    }
    

    二、错误,自行定义一个标志,用来判断是否继续执行(使用volatile)

    貌似可以中断线程,但实则遇到阻塞就无法中断线程

    /**
     * 自定义变量使用volatile修饰.来中断线程
     */
    public class MyInterruptDemo implements Runnable {
    
        private static volatile   boolean FLAG = true;
    
        @Override
        public void run() {
            while (FLAG) {
                System.out.println(Thread.currentThread().getName());
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread thread = new Thread(new MyInterruptDemo());
            thread.start();
            Thread.sleep(1000L);
            FLAG = false;
        }
    }
    

    陷入阻塞时,volatile是无法中断线程

    演示用volatile的局限part2 陷入阻塞时,volatile是无法中断线程的 此例中,生产者的生产速度很快,
    消费者消费速度慢,所以阻塞队列满了以后,生产者会阻塞,等待消费者进一步消费

    
    /**
     * 描述: 演示用volatile的局限part2 陷入阻塞时,volatile是无法中断线程的 此例中,生产者的生产速度很快,
     * 消费者消费速度慢,所以阻塞队列满了以后,生产者会阻塞,等待消费者进一步消费
     */
    public class WrongWayVolatileCantStop {
    
        public static void main(String[] args) throws InterruptedException {
            ArrayBlockingQueue storage = new ArrayBlockingQueue(10);
    
            Producer producer = new Producer(storage);
            Thread producerThread = new Thread(producer);
            producerThread.start();
            Thread.sleep(1000);
    
            Consumer consumer = new Consumer(storage);
            while (consumer.needMoreNums()) {
                System.out.println(consumer.storage.take()+"被消费了");
                Thread.sleep(100);
            }
            System.out.println("消费者不需要更多数据了。");
    
            //一旦消费不需要更多数据了,我们应该让生产者也停下来,但是实际情况
            producer.canceled=true;
            System.out.println(producer.canceled);
        }
    }
    
    class Producer implements Runnable {
    
        public volatile boolean canceled = false;
    
        BlockingQueue storage;
    
        public Producer(BlockingQueue storage) {
            this.storage = storage;
        }
    
    
        @Override
        public void run() {
            int num = 0;
            try {
                while (num <= 100000 && !canceled) {
                    if (num % 100 == 0) {
                        storage.put(num);// 阻塞在这步,导致无法中断线程
                        System.out.println(num + "是100的倍数,被放到仓库中了。");
                    }
                    num++;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("生产者结束运行");
            }
        }
    }
    
    class Consumer {
    
        BlockingQueue storage;
    
        public Consumer(BlockingQueue storage) {
            this.storage = storage;
        }
    
        public boolean needMoreNums() {
            if (Math.random() > 0.95) {
                return false;
            }
            return true;
        }
    }
    

    三、Thread.stop()方法(废弃,不能使用会造成严重事故)

    /**
     * 使用thread.stop()停止线程,不要使用
     */
    public class Demo implements Runnable {
        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
    
        public static void main(String[] args) throws InterruptedException {
            Thread thread = new Thread(new Demo());
            thread.start();
            Thread.sleep(2000L);
            thread.stop();
        }
    }
    

    四、interrupt需要注意的

    注意如下操作会清空清空中断标识

    • 调用Thread.interrupted()方法可以获取中断状态并会清空中断标识
    • 抛出InterruptedException异常会清空中断标识

    当run方法中存在sleep或wait方法时,停止线程需要注意可能会抛出InterruptedException异常会,导致中断失败,需要注意try--catch的用法

    4.1 循环里面放try/catch,会导致中断失效

    /**
     * 描述:     如果while里面放try/catch,会导致中断失效
     */
    public class CantInterrupt {
    
        public static void main(String[] args) throws InterruptedException {
            Runnable runnable = () -> {
                int num = 0;
                while (num <= 10000 && !Thread.currentThread().isInterrupted()) {
                    if (num % 100 == 0) {
                        System.out.println(num + "是100的倍数");
                    }
                    num++;
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            Thread thread = new Thread(runnable);
            thread.start();
            Thread.sleep(5000);
            thread.interrupt();
        }
        /**
         * 此时虽然调用了thread.interrupt();方法,但是由于线程的状态存在阻塞,
         * 所以会抛出java.lang.InterruptedException: sleep interrupted异常
         * 如果在循环里面放try/catch,会导致中断失效,即使捕获了异常也不会停止线程
         *
         * 输出结果如下
         *
         * 0是100的倍数
         * 100是100的倍数
         * 200是100的倍数
         * 300是100的倍数
         * 400是100的倍数
         * java.lang.InterruptedException: sleep interrupted
         *  at java.lang.Thread.sleep(Native Method)
         *  at com.liyc.concurrency.threadcoreknowledge.stopthreads.CantInterrupt.lambda$main$0(CantInterrupt.java:17)
         *  at java.lang.Thread.run(Thread.java:748)
         * 500是100的倍数
         * ...
         *
         *
         */
    }
    

    4.2 如果在执行过程中,每次循环都会调用sleep或wait等方法,那么不需要每次迭代都检查是否已中断

    /**
     * 描述: 如果在执行过程中,每次循环都会调用sleep或wait等方法,那么不需要每次迭代都检查是否已中断
     */
    public class RightWayStopThreadWithSleepEveryLoop {
        public static void main(String[] args) throws InterruptedException {
            Runnable runnable = () -> {
                int num = 0;
                try {//在循环外卖try catch可以捕获异常,并中断异常
                    while (num <= 10000) {
                        if (num % 100 == 0) {
                            System.out.println(num + "是100的倍数");
                        }
                        num++;
                        Thread.sleep(10);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            Thread thread = new Thread(runnable);
            thread.start();
            Thread.sleep(2000);
            thread.interrupt();
        }
        /**
         * 如果在执行过程中,每次循环都会调用sleep或wait等方法,那么不需要每次迭代都检查是否已中断
         * 
         * 输出结果:
         * 0是100的倍数
         * 100是100的倍数
         * java.lang.InterruptedException: sleep interrupted
         *  at java.lang.Thread.sleep(Native Method)
         *  at com.liyc.concurrency.threadcoreknowledge.stopthreads.RightWayStopThreadWithSleepEveryLoop.lambda$main$0(RightWayStopThreadWithSleepEveryLoop.java:16)
         *  at java.lang.Thread.run(Thread.java:748)
         */
    }
    

    相关文章

      网友评论

        本文标题:4.1、线程中断

        本文链接:https://www.haomeiwen.com/subject/ttfvsktx.html