Вы говорите здесь о грациозном завершении работы вашего приложения, должно делать следующее?
- дождитесь окончания очереди или
- тайм-аут, если сток занимает слишком много времени
Мне может понадобиться понять, как вы истощаете очередь, но если вы можете сделать это таким образом, чтобы она была прерываемой, вы можете установить тайм-аут при получении Future
и попробовать shutdownNow
( прерывая, если не полностью истощена) независимо; как это выглядит для вас?
ExecutorService pool = Executors.newSingleThreadExecutor();
public void stop() {
try {
pool.submit(new DrainTask()).get(100, MILLISECONDS);
} catch (TimeoutException e) {
// nada, the timeout indicates the queue hasn't drained yet
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
// nada, defer to finally
} finally {
pool.shutdownNow();
}
}
private class DrainTask implements Callable<Void> {
@Override
public Void call() throws Exception {
while (!Thread.currentThread().isInterrupted())
; // drain away
return null;
}
}
Используется ли деталь compareAndSet
для защиты от нескольких одновременных вызовов на stop
? Я думаю, что предпочел бы общий замок или использовал бы вместо него synchronized
. Однако в случае конфликта выдается ExecutionException
, и повторные вызовы на shutdownNow
подойдут.
Это отчасти зависит от способности DrainTask
останавливать то, что он делает в ответ на вызов прерывания (так как shutdownNow
будет пытаться вызвать прерывание на любых работающих в данный момент потоках).