Где поймать InterruptedException для Object.wait () с синхронизированным блоком?

Насколько я понимаю, это очень распространенный фрагмент для многопоточности в Java.

boolean loaded = false;
Object lock = new Object();

public void block() {
    synchronized (lock) {
        while(!loaded)
            lock.wait();//Unhandled exception type InterruptedException
    }
}

и в другом потоке

public void done() {
    synchronized (lock) {
        loaded = true;
        lock.notify();
    }
}

Но я не уверен, куда я должен поставить try и catch, я могу окружить весь синхронизированный блок или только lock.wait() ? Что такое эмпирическое правило и действительно ли это важно?

Для обработки это нормально вызвать Thread.currentThread (). Interrupt() в этой ситуации?

4
nl ja de
A) Если ваш поток получил прерывание, самое разумное - вызвать Thread.currentThread (). Interrupt() и выйти. B) Вы должны использовать примитивы синхронизации высокого уровня - Queues, например, C). Вы должны использовать notifyAll вместо уведомления D), вы должны прочитать некоторую книгу о многопоточности, например, Java Concurrency In Practice by Goetz
добавлено автор Boris Treukhov, источник
Ответ Андрея правильный, но я думаю, что распространенное исключение с ключевым словом throws не лучший всегда , потому что вы можете выполнить некоторую логику выключения (я имею в виду что-то, кроме закрытия ресурсы, которые выполняются в finally или в try-with ) - проблема в том, что, наконец, она зарезервирована для других исключительных ситуаций (не только прерванных исключений), а некоторая логика не подходит там очень хорошо - так что клиентский код (и его поток) будет менее читабельным.
добавлено автор Boris Treukhov, источник
Просто перефразируйте - когда вы разрабатываете примитив синхронизации, вы не можете делать ничего другого, кроме распространения этого исключения (примитив не имеет дополнительной логики), но когда вы пишете некоторый код с несколькими потоками, используя распространение с помощью throws заставит вас спроектировать вашу логику вокруг захвата InterruptedException, но InterruptedException - это то, что вероятнее всего происходит только при остановке JVM. Да, есть некоторые ситуации, когда разработка программы вокруг исключения в порядке (например, TimeoutException), но я думаю, что это не решение по умолчанию.
добавлено автор Boris Treukhov, источник
@BorisTreukhov, можете ли вы подробнее остановиться на этом? Но я не уверен, что положить проверенное исключение на все методы в стеке - лучшее решение ». Я не совсем понимаю, что это значит
добавлено автор Nikolay Kuznetsov, источник
лично, когда я использую эти механизмы (см. комментарий от @Boris Treukhov выше), я помещаю catch сразу вокруг вызова wait ()
добавлено автор radai, источник

2 ответы

You might want to consider the article by Brian Goetz: Java theory and practice: Dealing with InterruptedException

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

Если по какой-то причине вам нужно добавить блок try/catch и обработать исключение, тогда Thread.currentThread (). Interrupt() будет делать, но повторное бросок может быть подходящим.

6
добавлено
@NikolayKuznetsov это не имеет особого значения, изменения в потоке программы, вызванные исключением, не имеют ничего общего с многопоточным. Важно то, что статус прерывания не должен быть потерян. Но я не уверен, что отличное исключение для всех методов в стеке - лучшее решение. Постскриптум Другое дело, что вызов notify() вместо notifyAll() всегда требует некоторых рассуждений о безопасности.
добавлено автор Boris Treukhov, источник
Да, я написал эту статью, прежде чем писать вопрос. Но мой главный вопрос выделен жирным шрифтом.
добавлено автор Nikolay Kuznetsov, источник

Но я не уверен, куда я должен поставить попытку и поймать, я могу окружить весь синхронизированный блок или только lock.wait ()? Что такое эмпирическое правило и действительно ли это важно?

lock.wait() is the only line that can throw an exception in your block method. So whether you put your try/catch around the wait or include the whole method body does not make a difference from an execution perspective (assuming you exit the loop in both cases of course - if you want to continue looping then the try/catch block should obviously be within the loop).

Другими словами, это только вопрос стиля - см. этот другой обсуждение . Я лично считаю, что это более читаемо:

try {
    synchronized (lock) {
        while (!loaded) {
            lock.wait();//Unhandled exception type InterruptedException
        }
    }
} catch (InterruptedException e) {
    //to ignore me or not to ignore me, that is the question
    Thread.currentThread().interrupt();
}

Для обработки можно нормально вызвать Thread.currentThread (). interrupt() в этой ситуации?

В первом примере ниже можно поймать InterruptedException и выйти из цикла без повторного прерывания потока, поскольку в любом случае метод run будет завершен, и поток будет умирать:

new Thread(new Runnable() {

    @Override
    public void run() {
        block();
    }
}).start();

Во втором примере, приведенном ниже, вы, безусловно, должны повторно прервать поток, чтобы позволить методу запуска узнать, была ли причина, из-за которой завершился block() , что загруженный стал истинным или что он был прерван:

public void run() {
    while(!Thread.currentThread().isInterrupted()) {
        loaded = false;
        System.out.println("Launching data load");
        block(); //if false has become true, loop, if interrupted, exit
    }
}

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

3
добавлено
Я думаю, что этот урок об уведомлении потока более приятный: tutorials.jenkov.com/java- параллелизм/поточно-signaling.html
добавлено автор android developer, источник
pro.jvm
pro.jvm
3 503 участник(ов)

Сообщество разработчиков Java Scala Kotlin Groovy Clojure Чат для нач-их: @javastart Наш сайт: projvm.com projvm.ru Наш канал: @proJVM Вакансии: @jvmjobs Конфы: @jvmconf

Java & Co
Java & Co
2 370 участник(ов)

Можно обсуждать с матом и без всё, что касается жабы, вплоть до холиваров. НЕ ИМЕЕТ ОТНОШЕНИЯ К САЙТУ JAVARUSH.RU ПРАВИЛА - https://t.me/javarush/75723 Вакансии сюда - https://telegram.me/joinchat/B7IzvUCnfo6d8t3yIxKguQ По вопросам - @thedude

learn.java
learn.java
1 888 участник(ов)

Чат для начинающих и не только Статистика: https://combot.org/chat/-1001083535868 Основной чат - @jvmchat

Java Underground
Java Underground
169 участник(ов)

https://vk.com/javatutorial

Javanese Questions
Javanese Questions
109 участник(ов)

Чат предназначен для обмена знаниями строго в формате в вопрос-ответ. Тема — Java, Kotlin и Android. Вопрос должен быть предварительно прогуглен, понятно и грамотно сформулирован, помечен хэштегами. Ответ — тем более. Куски кода размером в несколько строк можно писать прямо здесь, для больших кусков кода стоит использовать http://gist.github.com/, http://pastebin.com/, https://codeshare.io/ или любой аналогичный сервис. В некоторых случаях можно прикреплять скриншоты. Стикеры и гифки запрещены. Дополнять и уточнять вопросы и ответы — редактированием исходного сообщения. Обсуждения должны приводить к редактированию вопроса/ответа и удаляться. По хештегам можно искать существующие вопросы и овтеты: #вопрос #ответ #git #generics #java #server #awt #javafx #swing #kotlin #anko #tornadofx #ktor #android #recyclerView #performance #arch #network #permissions #storage #async