2010-05-25 13 views
11

Cuando creo un hilo llamando a ScheduledExecutorService.schedule(), nunca termina después de ejecutar la tarea programada.¿Por qué el subproceso iniciado por ScheduledExecutorService.schedule() nunca termina?

Por ejemplo, el siguiente programa no se cierra:

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() { 
} 

¿Es esto un error de JDK, o qué acabo de perder algo?

+0

¿Qué está pasando en doSomething()? –

Respuesta

2

Debe llamar al scheduledExecutorService.shutdown() para detener la ejecución. De lo contrario, se reinicia cada segundo.

(Editado: ver comentarios)

+2

Debería llamar a ScheduleService.shutdown() en lugar de scheduleFuture.shutdown(), y ScheduledExecutorService.schedule() la llamada es una acción única, que nunca se reiniciará de nuevo. – moonese

7

Una tarea programada o bien se está ejecutando o está a la espera de ser ejecutado.

Si la tarea está esperando a ejecutarse, future.cancel() impedirá que se ejecute (tanto cancelar (verdadero)/cancelar (falso)).

Si la tarea ya se está ejecutando, future.cancel(false) no tendrá ningún efecto. future.cancel(true) interrumpirá el hilo que está ejecutando esa tarea. Si esto tendrá algún efecto depende de usted, quien implementará esa tarea. Una tarea puede o no responder a la interrupción dependiendo de la implementación.

Para que su tarea responda a la cancelación, debe implementar doSomething() para que responda a la interrupción.

Básicamente, hay dos manera de hacer esto:

1.Verificar bandera de interrupción en su lógica de

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(); 
} 

Debe comprobar de vez en cuando por la bandera de interrupción, y si se interrumpe, detener lo que está haciendo y volver. Asegúrese de utilizar Thread.isInterrupted() y no Thread.interrupt() para el control.

2.Act a excepción interrumpida

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(); 
} 

Cuando usted tiene cualquier método que lanza InterruptedException, asegúrese de dejar lo que hacer y terminar cuando uno se lanza.

Una vez que implemente sus métodos de esta manera, puede llamar a future.cancel (true) para cancelar la ejecución de una tarea en ejecución.

+0

¿Cómo cerrar el programa después de llamar al comando? Para liberar el recurso de hilo. Después de todo, la tarea creada por programación se ejecuta una vez. – Nickolas

+0

@Nickolas: No estoy seguro de lo que quiere decir, pero si se refiere a una tarea que estaba programada para ejecutarse una vez (después de un retraso, etc.) Y ya se completó, la tarea ya se habría detenido (y lanzado el hilo). De lo contrario, mi respuesta sigue siendo válida. –

+1

Esta es una buena respuesta, pero a una pregunta diferente. El problema no es cómo terminar la tarea (el OP indica explícitamente que la tarea es un nop) sino cómo finalizar el hilo utilizado para ejecutar la tarea. – oberlies

5

Su programa nunca finaliza porque crea un ScheduledExecutorService, que contiene un grupo de subprocesos, pero nunca cierra el servicio. Por lo tanto, los subprocesos de usuario en el grupo de subprocesos nunca se terminan y, por lo tanto, la VM se ejecuta constantemente.

Para resolver este problema, debe llamar al shutdown() en el servicio del ejecutor. Esto incluso puede realizarse directamente después de programar la tarea que desea ejecutar:

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(); 
} 

Esto ejecutará la tarea programada normalmente y luego terminar la hebra en la piscina.

Cuestiones relacionadas