Является ли это потокобезопасным способом обработки блокировки?

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

Можно использовать флаг (назовем его hasResource), который никак нельзя синхронизировать с другими потоками, чтобы указать, что поток не хочет прерываться. Никакая другая синхронизация вообще не допускается.

Является ли следующий безопасным способом справиться с этим сценарием?

@Override // we're subclassing Thread
public void run () {
    try {
        while (!interrupted ()) {
            blockingOpen ();
            // glitch possibility in this line
            hasResource = true;
            blockingClose ();
            hasResource = false;
        }
    }
    catch (final InterruptedException e) {
        interrupt ();
    }
}

В частности, гарантирует ли это, что поток не будет прерван, пока у него есть ресурс?

Насколько я могу судить, есть только одно окно возможности ошибки, сразу после открытия и перед установкой флажка. Однако похоже, что это привело бы не к утечке ресурса, а к случайному игнорированию запроса на прерывание. Можно ли это предотвратить?


person mafu    schedule 17.05.2014    source источник
comment
На самом деле, что касается моего последнего абзаца, выдает ли Thread.sleep() IE, если поток уже был прерван, когда начался сон? Это изменило бы ситуацию. В javadoc нет четкого указания в любом случае.   -  person mafu    schedule 17.05.2014
comment
Добавлен как отдельный вопрос: stackoverflow.com/questions/23710025   -  person mafu    schedule 17.05.2014
comment
Пробовали ли вы прерывать во время сна после прерывания? Я полагаю, что такое поведение легче проверить и оно поможет получить ответ на первоначальный вопрос.   -  person nanofarad    schedule 17.05.2014
comment
Делаю это прямо сейчас :)   -  person mafu    schedule 17.05.2014
comment
Интересно, что попытка заснуть срабатывает, если прерванная квартира была установлена ​​ранее.   -  person mafu    schedule 17.05.2014


Ответы (2)


Исходный код на самом деле правильный. Установка логического флага не является проблемой, хотя вопрос ошибочно предполагает, что это может быть. Есть два момента, которые необходимо учитывать, чтобы это было ясно:

Во-первых, сама строка не может вызвать ошибку. Если открытие прошло успешно, флаг будет установлен всегда. Здесь не может возникнуть даже StackOverflow или OutOfMemory.

Во-вторых, если interrupt() вызывается, когда не выполняется прерываемый код (например, сон), то будет установлен флаг interrupted. В следующий раз, когда начнется выполнение любого прерываемого кода, этот флаг будет проверен, и вместо запуска кода будет выдано исключение Interrupted.

Таким образом, исходный код действительно работает так, как задумано.

person mafu    schedule 14.08.2017
comment
А, теперь я вижу, в чем тогда заключалась ваша проблема. Это все еще оставляет нерешенным вопрос о закрытии ресурса, но я полагаю, что исходный вопрос на самом деле не требует этого. - person user1643723; 15.08.2017

Можно использовать флаг (назовем его hasResource), который никак нельзя синхронизировать с другими потоками, чтобы указать, что поток не хочет прерываться. Никакая другая синхронизация вообще не допускается.

Нет, это не так.

гарантирует ли это, что поток не будет прерван, пока у него есть ресурс?

Нет. Если hasResource является volatile и все остальные ваши потоки знают о hasResource и наблюдают за этим, то вы запретили себе вызывать Thread.interrupt(), но вы не запретили Java делать это.

Почему ваши потоки приложений будут прерывать друг друга, это другой вопрос. Никогда не использовал эту функцию в течение 20 лет.

person user207421    schedule 14.08.2017
comment
На самом деле, в этом конкретном случае Thread.interrupt() можно заблокировать — поскольку @mafu переопределяет поток, он также может переопределять Thread.interrupt(), чтобы проверять флаг и игнорировать прерывание, когда это необходимо. Кстати, никогда не использовал эту функцию за 20 лет — вы никогда не использовали Executor или Future? Большинство фреймворков потоковой передачи в Java используют прерывание потока для отмены задач. Это может быть непопулярно среди серверных программистов, но когда программисты настольных/мобильных компьютеров игнорируют его, мы получаем такие чудеса, как непрерывные зависшие загрузки или задачи компиляции, которые нельзя остановить часами. - person user1643723; 15.08.2017