Всякий раз, когда я вызываю shutdownNow()
или shutdown()
, он не закрывается. Я читал несколько тем, где говорилось, что закрытие не гарантировано - может ли кто-нибудь предоставить мне хороший способ сделать это?
Как закрыть службу-исполнитель?
Ответ 1
Типичный шаблон:
executorService.shutdownNow();
executorService.awaitTermination();
При вызове shutdownNow
исполнитель (обычно) пытается прервать потоки, которыми он управляет. Чтобы сделать shutdown изящным, вам нужно поймать прерванное исключение в потоках или проверить прерванный статус. Если ваши потоки не будут выполняться вечно, и ваш исполнитель никогда не сможет завершить работу. Это связано с тем, что прерывание потоков в Java является совместным процессом (т.е. прерванный код должен что-то делать, когда его просят остановить, а не прерывания).
Например, следующий код печатает Exiting normally...
. Но если вы закомментируете строку if (Thread.currentThread().isInterrupted()) break;
, она будет печатать Still waiting...
, потому что потоки внутри исполнителя все еще запущены.
public static void main(String args[]) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.submit(new Runnable() {
@Override
public void run() {
while (true) {
if (Thread.currentThread().isInterrupted()) break;
}
}
});
executor.shutdownNow();
if (!executor.awaitTermination(100, TimeUnit.MICROSECONDS)) {
System.out.println("Still waiting...");
System.exit(0);
}
System.out.println("Exiting normally...");
}
В качестве альтернативы он может быть записан с помощью InterruptedException
следующим образом:
public static void main(String args[]) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.submit(new Runnable() {
@Override
public void run() {
try {
while (true) {Thread.sleep(10);}
} catch (InterruptedException e) {
//ok let get out of here
}
}
});
executor.shutdownNow();
if (!executor.awaitTermination(100, TimeUnit.MICROSECONDS)) {
System.out.println("Still waiting...");
System.exit(0);
}
System.out.println("Exiting normally...");
}
Ответ 2
Лучший способ - это то, что мы имеем в javadoc, которое:
Следующий метод отключает ExecutorService в две фазы, сначала вызовите
shutdown
, чтобы отклонить входящие задачи, а затем вызовитеshutdownNow
, если необходимо, для отмены любых затяжных задач:
void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
pool.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}