【问题标题】:Thread Interrupt while sleeping睡眠时线程中断
【发布时间】:2016-03-28 08:27:30
【问题描述】:

在下面的示例中,我试图优雅地终止两个线程。消费者线程在睡眠时被中断,这应该将 isInterrupted 标志设置为 true。但是 !Thread.currentThread().isInterrupted() 对 while 循环的检查似乎仍然返回 = false,因为它不会终止使用者线程。

将以下代码复制粘贴到IDE中进行检查:

public class ThreadInterruptExample {

public static void main(String[] args) throws InterruptedException {
    LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>(1);
    ThreadInterruptExample ie = new ThreadInterruptExample();
    Producer producer = ie.new Producer(queue);
    Consumer consumer = ie.new Consumer(queue, producer);
    producer.start();
    consumer.start();
    Thread.sleep(1000);
    producer.cancel();
    consumer.cancel();
}

class BaseQueue extends Thread {
    protected final BlockingQueue<String> queue;

    public BaseQueue(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    public void cancel() {
        System.out.println(this.getName() + " - Shutting down");
        interrupt();
    }
}

class Producer extends BaseQueue {
    private final List<String> messages = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q",
            "r", "s", "t", "u", "v", "w", "x", "y", "z");

    public Producer(BlockingQueue<String> queue) {
        super(queue);
        this.setName("Producer");
    }

    public void run() {
        try {
            for (String message : messages) {
                System.out.println(this.getName() + ": Sending " + message);
                queue.put(message);
            }
        } catch (InterruptedException e) {
            System.out.println(this.getName() + " - InterruptedException occurred");
        }
    }
}

class Consumer extends BaseQueue {
    private final BaseQueue producer;

    public Consumer(BlockingQueue<String> queue, BaseQueue producerQueue) {
        super(queue);
        this.setName("Consumer");
        producer = producerQueue;
    }

    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            System.out.println(this.getName() +": Consumer Running");
            String message = "";
            try {
                Thread.sleep(1500);
                message = queue.take();
                System.out.println(this.getName() + ": Recevied " + message);
                if (message.equals("pill")) {
                    producer.cancel();
                    this.cancel();
                }
            } catch (InterruptedException e) {
                System.out.print(this.getName() + ": Exception occurred for: " + message);
                e.printStackTrace();
            }
        }
    }

}

}

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    当您捕获 InterruptedException 时,您正在丢弃中断。有两种解决方案。

    while (!Thread.currentThread().isInterrupted()) {
        try {
            Thread.sleep(1500);
    
        } catch (InterruptedException e) {
            Thread.currentThread.interrupt();
        }
    }
    

    或者更简单的是只在循环外捕获异常。

    try {
        while (!Thread.currentThread().isInterrupted()) {
            Thread.sleep(1500);
        }
    } catch (InterruptedException e) {
        Thread.currentThread.interrupt();
    }
    

    编辑:我认为这只是一个练习,因为使用 ExecutorService 会简单得多

    public static void main(String[] args) throws InterruptedException {
        ExecutorService service = Executors.newSingleThreadExecutor();
    
        for (String message : "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z".split(",")) {
            System.out.println(getThreadName() + ": Sending " + message);
            service.submit(() -> {
                System.out.println(getThreadName() + ": Recevied " + message);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    System.out.println("--- Interrupted");
                }
            });
        }
        service.shutdown();
        service.awaitTermination(1, TimeUnit.SECONDS);
        service.shutdownNow();
    }
    
    public static String getThreadName() {
        return Thread.currentThread().getName();
    }
    

    打印

    main: Sending a
    main: Sending b
    main: Sending c
    main: Sending d
    main: Sending e
    main: Sending f
    main: Sending g
    main: Sending h
    main: Sending i
    main: Sending j
    main: Sending k
    main: Sending l
    main: Sending m
    main: Sending n
    main: Sending o
    main: Sending p
    main: Sending q
    main: Sending r
    main: Sending s
    main: Sending t
    main: Sending u
    main: Sending v
    main: Sending w
    main: Sending x
    main: Sending y
    main: Sending z
    pool-1-thread-1: Recevied a
    pool-1-thread-1: Recevied b
    --- Interrupted
    

    【讨论】:

    • 感谢您提供的替代示例。你的建议很管用。我不明白为什么需要重新中断消费者的异常。我已经调用了一次consumer.cancel() -> 它将调用interrupt()。因此为什么它会引发异常。为什么我必须再次使用: Thread.currentThread.interrupt(); ?
    • @ShivamSinha 一旦你触发了一个 InterruptedException 信号就会被清除,这样线程就可以用于其他事情了。它假定您已经处理了catch 块中的中断,并且无需将其留在该状态。注意:没有办法取消设置中断。
    【解决方案2】:

    javadocs中所示

    如果此线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法或 join()、join(long)、join(long , int), sleep(long) 或 sleep(long, int) 方法,则其中断状态将被清除并收到 InterruptedException。

    所以在你的情况下,当调用中断时消费者正在睡觉,中断状态被清除,你收到一个 InterruptedException ,你可以决定下一步做什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-24
      • 2011-05-14
      • 2012-12-22
      • 2018-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-11
      相关资源
      最近更新 更多