Попытка Java наконец изменения

Этот вопрос ворчит меня некоторое время, но я еще не сделал найденного полного ответа на него (например, этот для C#, Инициализирующего доступные ресурсы внутри или снаружи попытки/наконец). Рассмотрите два после фрагментов кода Java:

Closeable in = new FileInputStream("data.txt");
try {
    doSomething(in);
} finally {
    in.close();
}

и второе изменение

Closeable in = null;
try {
    in = new FileInputStream("data.txt");
    doSomething(in);
} finally {
    if (null != in) in.close();
}

Часть, которая волнует меня, - то, что поток мог бы быть несколько прерван между ресурсом момента, получен (например, файл открыт), но получающееся значение не присвоено соответствующей локальной переменной. Есть ли любые другие сценарии, кроме которых поток мог бы быть прерван в точке выше:

  1. InterruptedException (например, через Thread#interrupt ()) или исключение OutOfMemoryError брошен
  2. Выходы JVM (например, через уничтожение, System.exit ())
  3. Аппаратный сбой (или ошибка в JVM для полного списка :)

Я читал, что второй подход несколько более "идиоматичен", но IMO в сценарии выше нет никакого различия, и во всех других сценариях они равны.

Так вопрос:

Каковы различия между двумя? Который я должен предпочесть, если я делаю касавшийся освобождения ресурсов (особенно в в большой степени приложениях многопоточности)? Почему?

Я ценил бы, если кто-либо указывает на меня на части спецификаций Java/JVM, которые поддерживают ответы.

5
задан Community 23 May 2017 в 12:19
поделиться

3 ответа

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

1) InterruptedException (например, через Thread # interrupt ())

Вызов Thread.interrupt () не вызывает спонтанного создания InterruptedException . Исключение возникает только в определенных (и хорошо задокументированных) методах блокировки; то есть блокирование методов ввода-вывода и синхронизации. Это исключение не может быть создано после возврата из конструктора потока и до входа в блок try.

или исключение OutOfMemoryError

Если выбрасывается OutOfMemoryError , вы не можете гарантировать полное восстановление базового дескриптора файла, независимо от того, куда вы поместили конструктор потока. Никогда не следует пытаться восстановиться после OOM, поэтому вопрос о том, закрыт ли поток, остается спорным.Кроме того, это исключение возникает только в потоке, который на самом деле пытается выделить память, а на данный момент этого не происходит.

2) JVM завершает работу (например, через kill, System.exit ())

Если приложение принудительно завершается с помощью внешнего kill или System.exit () , не имеет значения, правильно ли закрываются потоки. Кроме того, в обоих случаях нет гарантии, что предложения finally будут выполнены.

3) Аппаратный сбой (или ошибка в JVM для полного списка:)

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

Есть еще одна ситуация, когда поток может получить спонтанное исключение в этот момент с некоторым (наивным) ожиданием, что он может восстановиться. Это когда какой-то заблуждающийся программист решает вызвать устаревший метод Thread.stop () . Вы можете подумать, что размещение вызова конструктора потока внутри блока try поможет. Но на самом деле этого не произойдет, потому что исключение ThreadDeath могло быть вызвано внутри конструктора потока между открытием базового файла и завершением построения объекта потока. Так что FD все равно может протечь.

Это лишь одна из причин, по которой Thread.stop () устарел. Не используйте это.

6
ответ дан 13 December 2019 в 19:23
поделиться

a) Обратите внимание, что прерывание потока с помощью interrupt () не вступит в силу немедленно , и может вообще не иметь никакого эффекта, если прерываемый поток не взаимодействует. Невозможно, чтобы поток завершился из-за прерывания () во время выполнения:

Closeable in = new FileInputStream("data.txt");

Единственное, что произойдет, это то, что его флаг прерывания потока будет установлен.

б) относительно OutOfMemoryError - я не понимаю, как это может произойти сразу после построения входного потока. Это может произойти в другом потоке, но это не окажет немедленного влияния на этот поток. Проблема с OutOfMemoryError заключается в том, что ваш блок finally также может выйти из строя, потому что недостаточно памяти для его завершения ...

c) Единственный способ, которым я знаю, что поток может быть прерван агрессивно, - это использовать устаревшие методы Thread. stop () и Thread.stop (Throwable). См. аналогичное обсуждение здесь: Является ли это безопасным способом высвобождения ресурсов в Java?

5
ответ дан 13 December 2019 в 19:23
поделиться

Я считаю, что когда вы работаете с управляемой средой выполнения, такой как Java или .NET, вам действительно не следует (и это хорошо!) Беспокоиться о таких вещах, как ваш конкретный вопрос. Только потому, что вы полностью отключены от базовой операционной системы и ее собственных API. Все, что вам нужно знать, это то, что вы вызываете Closable.close () в своем блоке finally , и ваш ресурс всегда будет освобожден.

0
ответ дан 13 December 2019 в 19:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: