Pregunta

Tengo un bucle de procesamiento del formulario.

while (true) {
    doWork();
    Thread.sleep(SLEEP_INTERVAL);
}

quiero hacer un Runnable fuera de esto que puede jugar bien con ExecutorService y cual saldrá cuando ExecutorService.shutdownNow() se llama.

Estoy buscando escribirlo de esta manera:

public WorkerTask implements Runnable
{
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            doWork();
            try {
                Thread.sleep(SLEEP_INTERVAL);
            }
            catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

Las pruebas simples muestran que al menos parece funcionar en el sentido de que la tarea se interrumpe y se cerrará y el ExecutorService se cerrará, y parece hacerlo si la interrupción llega mientras doWork() está procesando o durante el sleep.(Al variar la cantidad de trabajo doWork() hace y que tan grande SLEEP_INTERVAL es que puedo controlar prácticamente dónde ocurre la interrupción).

Pero cuando busco en Google veo ejemplos usando Thread.interrupted() así como Thread.currentThread().isInterrupted().Entiendo que el primero borra la bandera interrumpida mientras que el segundo la abandona, pero ¿hay alguna otra diferencia que deba preocuparme?

También veo versiones donde el resultado de Thread.currentThread().isInterrupted() o Thread.interrupted() se almacena en un volatile variable y esa variable se utiliza como while condición de prueba de bucle.¿Es solo un estilo o es necesario hacerlo?En lo que he escrito, ¿tengo que preocuparme de que de alguna manera algo pueda borrar el indicador de interrupción entre el momento en que se establece (ya sea al recibirlo cuando el hilo está activo o al capturarlo? InterruptedException y reafirmar la bandera) y cuando Thread.currentThread().isInterrupted() ¿Se llama en la prueba del bucle?

¿Fue útil?

Solución

Tu código me parece bien.Introducir una variable volátil adicional sería una complejidad innecesaria:el estado de interrupción hace el trabajo.

La forma recomendada, en Concurrencia de Java en la práctica, lidiar con interrupciones en las tareas es lanzar un InterruptedException (Esto es factible si la tarea es una Callable y no un Runnable), o para asegurarse de que el estado de interrupción esté establecido y salir de la tarea lo antes posible.Tu código lo hace bien.

Otros consejos

¿Podrías echarle un vistazo? ScheduledExecutorService si coincide con sus requisitos:

 class BeeperControl {
    private final ScheduledExecutorService scheduler =
      Executors.newScheduledThreadPool(1);

    public void beepForAnHour() {
      final Runnable beeper = new Runnable() {
        public void run() { System.out.println("beep"); }
      };
      final ScheduledFuture<?> beeperHandle =
        scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
      scheduler.schedule(new Runnable() {
        public void run() { beeperHandle.cancel(true); }
      }, 60 * 60, SECONDS);
    }
  }}

Básicamente deberías aprovechar java.util.concurrent bibliotecas aquí. Debe enviar su tarea a través de ExecutorService.submit()y luego llamar a métodos de bloqueo como Future.get() , entonces puede estar seguro de que esos métodos responderán a la interrupción lo antes posible lanzando un ExecutionException() Probablemente deberías deshacerte de ese Thread.sleep() ya que no hace nada.Desea detectar una interrupción lo más rápido posible. Es posible que también desee esperar un tiempo de espera en caso de que su tarea esté haciendo algo infinitamente.Entonces, si la tarea termina con TimeOutException, la tarea se cancela a través de su Future.Yo lo llamo cancel() incondicionalmente ya que cancelar una tarea completada no tiene ningún efecto.En ese caso puedes hacer algo como:

 public static void main(String[] args) {
    WorkerTask runnable;
    TimeUnit unit;
    Future<?>   task = executor.submit(workerTask);
    try{
      task.get(timeout,unit);
    } catch(TimeoutException e){

    }catch(ExecutionException e){
        throw e.getCause();  
    } finally{
      //Harmless if the task already completed
      task.cancel(true);
    }
  }
}      
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top