Прерывание, вызванное в потоке, не генерирует Interrupted Exception, когда поток блокируется

Я пытаюсь реализовать очередь блокировки (только на стороне потребителя) с ReentrantLock и условиями, но нахожусь в состоянии, когда JVM не завершается. Странно то, что один поток прерывается, а другой нет. Я уверен, что делаю какую-то ошибку, но просто не могу понять, что.

РЕДАКТИРОВАТЬ:

Основной вопрос: почему только один поток генерирует исключение interruptedexception, когда оба потока блокируются в условии.

Итак, приведенный ниже код — это просто пример, который я создал. Основная проблема заключалась в разработке реализации производитель-потребитель, в которой я должен был создать класс моделирования, который порождал два типа потоков, клиентов и поваров, которые были синхронизированы на основе блокировки повторного входа. После того, как некоторые операции были выполнены (клиенты добавляют заказы, а повара выполняют эти заказы), я вызываю соединение в потоках клиентов, чтобы убедиться, что все заказы были обработаны, а затем, чтобы остановить потоки поваров, я вызвал прерывание в потоках поваров, чтобы завершить их. . Но только один поток выдает прерванное исключение, а второй нет. Это почему? так как оба потока блокируются в ожидании.

Мой код выглядит следующим образом:

Класс потока:

public class InterruptedThread implements Runnable{

    private final Lock lock;
    private final Condition condition;
    private final Queue<Integer> orderQueue;


    public InterruptedThread(Lock lock, Condition condition,Queue<Integer> orderQueue)
    {
        this.lock = lock;
        this.condition = condition;
        this.orderQueue = orderQueue;
    }

    @Override
    public void run() {

        try{
        while(true)
        {
            this.lock.lockInterruptibly();
            while(orderQueue.size() == 0 && !Thread.currentThread().isInterrupted())
            {
                   System.out.println("Inside blocking wait" + Thread.currentThread().getName());
                   condition.await();
            }

            int i = orderQueue.poll().intValue();
            System.out.println("Value read:" + i + "by thread" + Thread.currentThread().getName());
            this.lock.unlock();


        }
        }
        catch(InterruptedException ex)
        {
            System.out.println("Interrupted exception" + Thread.currentThread().getName());
            this.condition.signalAll();
            Thread.currentThread().interrupt();

        }

    }

}

Основной класс:

public class ExplicitLockCondition {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here

        Queue<Integer> orderQueue = new LinkedList<>();
        Lock lock = new ReentrantLock();
        Condition testCondition = lock.newCondition();

        Thread[] ths = new Thread[2];
        for(int i=0; i<ths.length;i++)
        {
            ths[i] = new Thread(new InterruptedThread(lock, testCondition,orderQueue));
            ths[i].start();
        }

        lock.lock();

        orderQueue.add(1);
        lock.unlock();

        lock.lock();
        orderQueue.add(2);
        lock.unlock();

        try {
            Thread.currentThread().sleep(5000);
        } catch (InterruptedException ex) {
            Logger.getLogger(ExplicitLockCondition.class.getName()).log(Level.SEVERE, null, ex);
        }

        lock.lock();
        orderQueue.add(-99);
        lock.unlock();


        for(int i=0; i<ths.length;i++)
        {
            ths[i].interrupt();

        }
        System.out.println("After loop exited!!!");
        for(int i=0; i<ths.length;i++)
        {
        System.out.println("Interrupted thread:" + ths[i].getName() +"with interrupt flag:" + ths[0].isInterrupted());
        }

        for(int i=0; i<ths.length;i++)
        {
            try {
                ths[i].join();
            } catch (InterruptedException ex) {
                Logger.getLogger(ExplicitLockCondition.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        System.out.println("Program exited!!!");

    }

}

person Muddassar Mubeen    schedule 21.03.2015    source источник


Ответы (2)


У вас есть

condition.await();

но единственное место, где вы signal, это блок catch.

При типичном выполнении вашего приложения ваш InterruptedThread (назовем его it1) войдет в цикл while, а await - в condition, переведя себя в состояние ожидания. Ваш поток main сделает кучу вещей и в конце концов прервет it1. Обратите внимание на javadoc Condition#await() заявляет

Во всех случаях, прежде чем этот метод сможет вернуть значение, текущий поток должен повторно получить блокировку, связанную с этим условием.

Таким образом, поток it2 снова получает блокировку, и поскольку он был прерван

Если текущий поток:

  • имеет установленный статус прерывания при входе в этот метод; или
  • прерывается во время ожидания и поддерживается прерывание приостановки потока,

затем выбрасывается InterruptedException, и статус прерванного текущего потока сбрасывается.

Таким образом, выполнение покидает блок while и переходит к блоку catch. В течение этого времени ваш поток it2 по-прежнему владеет блокировкой, так как ничто не unlock его изменило. Затем блок catch вызывает

this.condition.signalAll();

который сигнализирует condition. Затем поток it1 завершается нормально. Тем не менее, Lock по-прежнему заблокирован, и ничто не может его заполучить, поэтому ваш другой InterruptedThread не может продолжать работу из своего

condition.await();

По сути, вам нужно лучше справляться с блокировкой и разблокировкой вашего Lock.

person Sotirios Delimanolis    schedule 21.03.2015
comment
Спасибо, блокировка не сдавалась той веткой, сейчас добавил более качественный код разблокировки. - person Muddassar Mubeen; 22.03.2015
comment
@SotiriosDelimanolis У меня есть аналогичный вопрос по InterruptedException здесь, что касается прерывания RestTemplate вызовов. Если возможно, вы можете мне помочь. Я знаю, что вы очень помогли мне в различных вопросах RestTemplate, так что вы могли бы помочь мне и в этом. Любая помощь будет оценена. Я до сих пор не могу найти хороший способ справиться с моей текущей проблемой. - person john; 22.03.2015
comment
@SotiriosDelimanolis Ты рядом? Извините, что снова обращаюсь к вам подобным образом. если у вас есть сегодня немного времени, мы можем поговорить о моем глупом вопросе, над которым я застрял на долгое время. - person john; 24.03.2015
comment
@Давид Привет. Я рядом, но у меня нет ответа на этот вопрос. Я мог бы посмотреть на это снова позже. - person Sotirios Delimanolis; 24.03.2015

а) вы никогда не сигнализируете об условии после того, как вставите значение в свою очередь

б) ваша нить уйдет

while(orderQueue.size() == 0 && !Thread.currentThread().isInterrupted())

если он прервался, а затем попытался опросить значение из очереди. Если там нет значения, будет возвращено значение null, и вы получите исключение неперехваченного нулевого указателя, но блокировка никогда не будет разблокирована.

Всегда

lock.lock()l
try {
...
} finally {
lovk.unlovk();

}

person Zielu    schedule 21.03.2015
comment
Спасибо, я следовал предложенному вами шаблону рефакторинга моего кода, теперь он работает. - person Muddassar Mubeen; 22.03.2015