2014-08-11 3 views
6

Много примеров использования ресурсов Java выглядеть следующим образом:Состояние ожидания Java-try-finally?

Resource r = openResource(); 
try { 
    // use resource 
} finally { 
    r.close(); 
} 

Декларация r должна быть вне try -clause, чтобы быть видимым в finally -clause, но это также делает его похожим есть потенциальное состояние гонки: Что делать, если есть прерывание потока прямо между openResource() -колл и ввод try -clause?

Может ли это означать, что ресурс не действительно закрыт в этом сценарии?

Или Java гарантирует, что try-finally охватывает r «полностью», несмотря на синтаксис, похожий на него?

Или я должен написать:

Resource r = null; 
try { 
    r = openResource(); 
    // use resource 
} finally { 
    if (r != null) r.close(); 
} 

в целях защиты от резьбы прерываний?

+1

Теоретически, да, есть проблема. На практике, однако, пока нет промежуточных утверждений, я сомневаюсь, что есть сценарий, в котором вы могли бы получить прерывание после возвращения из 'openResource' и перед входом в область' try'. Реальная экспозиция будет находиться внутри 'openResource', которая должна была быть установлена ​​до' r' и, следовательно, вне контроля вызывающего абонента. –

ответ

3

Что делать, если есть прерывание потока справа между вызовом openResource() и вводом аргумента try?

Затем нить не будет выбрасывать InterruptedException, пока не ударит какой-либо блокирующий вызов. Этого не может произойти до того, как он попадет в блок try, потому что не больше не блокирует вызовы, предполагая, что метод действительно возвращается. Из документов для InterruptedException:

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

Обратите внимание, что даже если вы сделать положить приобретение внутри try блока, что на самом деле не допустить каких-либо условий гонки, которые могли бы существовать - потому что вы будете полагаться на метод или конструктор возвращающегося в первое место. Если может произойти исключение после метод/конструктор возвращает, почему он не может произойти перед он возвращается, но после того, как ресурс был приобретен? Если это произойдет, вы ничего не можете назвать close ...

Я по-прежнему рекомендую использовать инструкцию try-with-resources в Java 7, но если вы посмотрите на JLS section 14.20.3.1, вы увидите, что расширение как вашего первого кусок коды:

смысл основного заявления примерочного с-ресурсов:

try ({VariableModifier} R Identifier = Expression ...) 
    Block 

дается следующим переводом на локальную переменную декларацию и примерку улов -значение :

{ 
    final {VariableModifierNoFinal} R Identifier = Expression; 
    Throwable #primaryExc = null; 

    try ResourceSpecification_tail 
     Block 
    catch (Throwable #t) { 
     ... 
     #primaryExc = #t; 
     throw #t; 
    } finally { 
     ... 
    } 
} 
+0

Здесь термин «состояние гонки» используется неправильно. –

+0

@HotLicks: На самом деле, я не уверен, что это так. Если это один поток, вызывающий 'interrupt()' в потоке, который обрабатывает ресурс, OP считает, что между прерыванием потока прерывается гонка, и она «достигает» блока try. –

+0

А, вы имеете в виду: http://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html и http://docs.oracle.com/javase/7/docs/api/java/lang/ InterruptedException.html - исключение возникает только при спящем/ожидании, а не в произвольных точках. – Jxtps

4

Этих примеров использования ресурсов Java может быть написан как пример, вы даете, где r изначально установлен в null, но если они использовали Java 7 try-with-resources синтаксиса (Предполагаются, что Resource орудие AutoCloseable):

try (Resource r = openResource()) { 
    // use resource 
} 

Тогда они будет эквивалентен первому примеру, где openResource() вызывается до блока try. Java Language Specification for the try-with-resources statement определяет семантику как эквивалентную для назначения переменной с инициализатором перед блоком, а затем ввода блока try-catch-finally.

Возникла проблема с исключением, произошедшим до ввода блока try. Проблема в основном теоретическая. Если openResource() возвращается нормально и нет никаких промежуточных утверждений между назначением r и началом блока try, то маловероятно, хотя и не невозможно, что какой-то другой поток получит контроль до того, как начнется блок try, но даже тогда, когда ваш поток снова запустился, и он не попал в блок try. Если другой поток сделал что-то, из-за чего JVM завершил работу, например, вызвав System.exit, вам обычно не нужно беспокоиться о закрытии ресурсов. И даже этот случай маловероятен.

Если, с другой стороны, возникла проблема с открытием ресурса, предположительно, будет openResource(), что предотвратит присвоение r.

+0

Я не верю, что это так - см. Мой ответ. Очевидно, что try-with-resources проще в любом случае ... –

+1

Также обратите внимание, что блок 'try-with-resources' также получает ресурс за пределами try/finally - см. Http://docs.oracle.com/javase/specs /jls/se8/html/jls-14.html#jls-14.20.3.1 –

+0

Я считаю, что Джон прав, в этом сценарии. Но использование стиля try-with-resource, вероятно, более «структурировано» и избегает нескольких ошибок в кодировании. –

3

Не существует потенциального состояния гонки. Вы либо получите исключение во время вызова getResource, либо он может вернуть нуль - но условия гонки отсутствуют. Если ваш поток был прерван, вы можете получить InterruptedException, но это помешает вам ввести блок.

+0

И следует отметить, что «условие гонки» должно быть зарезервировано для двух (или более) потоков «одновременно» для доступа/обновления одного и того же ресурса. В этом случае любое исключение будет синхронным с текущим потоком, даже если оно каким-то образом спровоцировано другим потоком. –

Смежные вопросы