2010-05-25 3 views
11

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

Например, следующая программа никогда не выходит:

public static void main(String[] args) { 
    ScheduledFuture scheduledFuture = 
     Executors.newSingleThreadScheduledExecutor().schedule(new Callable() { 

    public Void call() { 
     doSomething(); 
     return null; 
    } 

    }, 1, TimeUnit.SECONDS); 
} 

public static void doSomething() { 
} 

Является ли это ошибка JDK, или я просто что-то пропустила?

+0

Что происходит в doSomething()? –

ответ

2

Чтобы остановить выполнение, вам необходимо позвонить scheduledExecutorService.shutdown(). В противном случае он перезапускается каждую секунду.

(Редакцией: см комментарии)

+2

Должен вызывать scheduleExecutorService.shutdown() вместо scheduleFuture.shutdown() и ScheduledExecutorService.schedule() - однократное действие, которое больше никогда не будет перезапущено. – moonese

7

Запланированная задача либо выполняется или ожидает выполнения.

Если задание ожидает выполнения, то future.cancel() предотвратит его выполнение (оба отменят (true)/cancel (false)).

Если задача уже выполнена, future.cancel(false) не будет иметь эффекта. future.cancel(true) прервет поток, выполняющий эту задачу. Будет ли это иметь какой-либо эффект, зависит от вас, кто выполнит эту задачу. Задача может или не может реагировать на прерывание в зависимости от реализации.

Для того чтобы ваша задача реагировала на отмену, вы должны реализовать doSomething() так, чтобы она реагировала на прерывание.

Есть в основном два способа сделать это:

1.check флаг прерывания в вашей логике

public void doSomething(){ 
    stuff(); 
    //Don't use Thread.interrupt() 
    if(Thread.currentThread().isInterrupted()){ 
     // We have an interruption request, possibly a cancel request 
     //Stop doing what you are doing and terminate. 
     return; 
    } 
    doLongRunningStuff(); 
} 

Вы должны периодически проверять флаг прерывания, и если прервано, остановить то, что вы делаете и вернуться. Обязательно используйте Thread.isInterrupted(), а не Thread.interrupt() для проверки.

2.Act на Прерванный исключением

public void doSomething(){ 
    try{ 
     stuff(); 
    }catch(InterruptedException e){ 
     // We have an interruption request, possibly a cancel request 

     // First, preserve Interrupted Status because InterruptedException clears the 
     // interrupted flag 
     Thread.currentThread.interrupt(); 

     // Now stop doing your task and terminate 
     return; 
    } 

    doLongRunningStuff(); 
} 

Если у вас есть какой-либо метод, который бросает InterruptedException, убедитесь, чтобы остановить то, что вы делаете, и заканчиваются, когда один брошен.

Как только вы реализуете свои методы таким образом, вы можете вызвать future.cancel (true), чтобы отменить выполнение выполняемой задачи.

+0

Как вызывать расписание после вызова команды? Чтобы освободить ресурс потока. В конце концов, задача, созданная по расписанию, выполняется один раз. – Nickolas

+0

@Nickolas: Не уверен, что вы имеете в виду, но если вы имеете в виду задачу, которая должна была запускаться один раз (после задержки и т. Д.) И она уже завершена, тогда задача уже остановилась (и выпустила поток). В противном случае мой ответ по-прежнему применяется. –

+1

Это хороший ответ, но на другой вопрос. Проблема заключается не в том, как прервать задачу - OP явно заявляет, что задача является nop-но как прекратить поток, используемый для запуска задачи. – oberlies

5

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

Для решения этой проблемы вам необходимо позвонить в службу поддержки shutdown(). Это может даже быть сделано непосредственно после планирования задачи вы хотите выполнить:

public static void main(String[] args) { 
    ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); 
    ScheduledFuture scheduledFuture = executorService.schedule(new Callable() { 

    public Void call() { 
     doSomething(); 
     return null; 
    } 

    }, 1, TimeUnit.SECONDS); 
    executorService.shutdown(); 
} 

Это будет выполнять запланированное задание нормально, а затем прекратить поток в бассейне.

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