2013-07-18 5 views
3

Я просто столкнулся с интересной проблемой. Кажется, что если в Java поток вызывает System.exit(), он не может быть присоединен через Thread.join().Java Threads and Shutdown Hook

Это вызывает у меня вопросы, как я хочу использовать отключения крюк для очистки после моего заявления, такие как:

Runtime.getRuntime.addShutdownHook(new Thread() { 
    public void run() { 
     reader.join(); 
     writer.join(); 
     in.close(); 
     out.close(); 
    } 
}); 

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

  1. Пользователь нажимает [ctrl] + [C].
  2. Поток для чтения завершается и вызывает System.exit().
  3. Writer thread завершает и вызывает System.exit().

Первый случай, когда пользователь нажимает [ctrl] + [C], работает нормально. Но в любом из двух других случаев блокировка блокировки блокируется навсегда. Это эффект детонации того факта, что один Thread.join(), который вызывается против потока, уже названного System.exit(), блокирует навсегда.

Таким образом, у меня есть 2 вопроса. Во-первых, я знаю, что вместо этого могу использовать Thread.join(long millis), чтобы они не блокировались бесконечно, но может ли кто-нибудь подумать о более элегантном решении? Во-вторых, хотя можно вызвать Thread.join() против одного и того же потока дважды, а во втором случае он сразу же вернется сразу, кто-нибудь знает причину, почему вызов Thread.join() против потока, который уже вызвал System.exit(), блокирует неопределенное время и не сразу возвращается сразу?

+5

Почему бы не попытаться избежать вызова 'System.exit()' и вместо этого организовать правильную очистку и позволить JVM выйти естественным путем? – assylias

+0

Также обратите внимание на то, что «* Если' System.exit() 'вызывается после того, как виртуальная машина начала свою последовательность выключения, тогда, если запускаются затворы остановки, этот метод будет блокироваться бесконечно. *" - вы называете 'System.exit() 'дважды случайно? ([Ссылка] (http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#exit%28int%29)) – assylias

ответ

0

Не рекомендуется использовать System.exit(), поскольку это просто завершает работу JVM. Существуют другие инструменты параллелизма, такие как CountDownLatch. Вы даже можете использовать окончательно, чтобы правильно очистить при выключении.

1

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

Обходным решением будет обычный стандартный замок (или даже просто взломать его с помощью new Thread(new Runnable() { public void run() { System.exit(0); }}).start();).

0

Используйте исполнителей и не используйте объединение или вручную создавайте потоки.

При использовании исполнителя и других вещей в java.util.concurrent вы можете просто вызвать shutdown и дождаться его завершения, указать тайм-аут и т. Д. Гораздо более надежный. Если вы используете java 1.7, попробуйте использовать ресурсы для закрытия ваших потоков. Таким образом, у вас не так много работы по очистке, что вы делаете за пределами выключения своего исполнителя. Если нет, используйте блок finally. Никогда не звоните нигде, кроме как из блока finally.

1

Что вы делаете specifically prohibited:

Shutdown крючки должны также закончить свою работу быстро.

Объединение случайных потоков не может быть описано как «быстрое».

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

+0

Спасибо за ваш ответ. Извиняюсь, чтобы попытаться держать мой вопрос коротким и точным, я, очевидно, опустил довольно много кода. Я на самом деле сначала вызываю метод против потоков, чтобы сказать им, что они должны закончить ASAP, прежде чем я вызову 'Thead.join()' s. К сожалению, потоки не имеют независимых ресурсов. Поэтому они не могут закрыть свои собственные ресурсы, если другой поток все еще использует их. – greydamian