并发编程

4.1、线程中断

2020-09-01  本文已影响0人  liyc712

线程的中断操作

一、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需要注意的

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

当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)
     */
}
上一篇 下一篇

猜你喜欢

热点阅读