2010-01-21 13 views
5

Quiero administrar una lista de objetos futuros devueltos por mi TaskExecutor.
tengo algo como estoJava Thread - Thread Thread.interrupted() y future.cancel (true) behavior

List<Future<String>> list 

void process(ProcessThis processThis) {  
    for (...) { 
     Future<String> future = taskExecutor.submit(processThis); 
     list.add(future) 
    } 
} 


void removeFutures() { 
    for(Future future : list) { 
     assert future.cancel(true); 
} 

ProcessThis es una tarea que se puede llamar implementa < cuerda> y cheques por Thread.interrupted() Estado

public String call() { 
     while (true) { 
      if (Thread.interrupted()) { 
       break; 
      } 
      doSomething(); 
     } 
    } 

Ahora el problema es que sólo un subconjunto de los Threads concurrentes vuelven a 'verdadero' cuando se invoca Thread.interrupted().
La afirmación en removeFutures() devuelve verdadero para cada futuro que se elimine (también compruebo isDone() y isCompleted()
El número de subprocesos que se interrumpen es aleatorio. Más de 15 subprocesos en ejecución a veces se interrumpen 13, a veces 2 ...
Realmente no entiendo dónde está el problema. Si llamo a future.cancel (verdadero) y esto devuelve cierto ... y luego reviso Thread.interrupted (esto se llama solo una vez), espero esto para volver cierto.
Cualquier idea de lo que me estoy perdiendo?

estoy en construcción java 1.6.0_02-b05

Respuesta

2

por lo menos, debe restaurar el interr uption bandera para hacer TaskExecutor consciente de la interrupción del hilo:

public String call() { 
    while (true) { 
     if (Thread.interrupted()) { 
      Thread.currentThread().interrupt(); 
      break; 
     } 
     doSomething(); 
    } 
} 
+0

gracias por su respuesta. ¿De qué sirve hacer esto? Si Thread.interrupted() devuelve true, rompo el ciclo while y básicamente elimino el hilo. El problema es que a veces Thread.interrupted() devuelve 'false' incluso si el future.cancel (true) relacionado devuelve true. La línea que editó no puede ser alcanzada en ese momento. – marts

+0

Entonces la bandera de interrupción probablemente se pierda en algún lugar de 'doSomething()' (por la misma razón: algo restablece la bandera y no se restaura en). Es decir, la muestra en mi respuesta es un principio básico que debe usarse para evitar interrupciones perdidas – axtavt

+0

Si ese es el caso ('evitar interrupciones perdidas') ¿no podría simplemente usar algo como Thread.currentThread(). IsInterrupted() en lugar de tener que restaurar el estado de interrupción cada vez que uso Thread.interrupted(). (Por cierto, hay un error con esto: http://stackoverflow.com/questions/2012259/) No estoy tratando con el estado de interrupción en doSomething. – marts

2

Un problema potencial que las interrupciones son a menudo tragan. Por lo tanto, en algún lugar en el fondo de doSomething() (o incluso en la carga de la clase), una interrupción puede ser capturada por, digamos, wait() y luego descartada por el código 'descuidado'. Las interrupciones son malas, IMO.

Puede valer la pena comprobar que todas las tareas se estén ejecutando en el momento de la cancelación.

6

Tenga en cuenta que Thread.interrupted() devuelve el estado interrumpido actual y luego lo borra, por lo que todas las invocaciones futuras devolverán falso. Lo que quiere es probablemente Thread.currentThread().isInterrupted().

También tenga en cuenta que future.cancel(true) generalmente solo devolverá falso si la tarea ya se ha completado o cancelado. Si devuelve verdadero, eso no es garantía de que la tarea realmente se cancelará.

¿Qué está pasando en doSomething()? Es posible que una RuntimeException se escape en algún lugar debido a la interrupción. ¿Tienes un conjunto de UncaughtExceptionHandler? De lo contrario, deberá pasar un ThreadFactory al Executor que configurará el manejador de excepciones y registrará las excepciones perdidas.

+0

Soy consciente de esto. Estoy llamando a Thread.interrupted() solo una vez después del tiempo {. De todas formas, si devuelve verdadero, me rompo; y mata el hilo de inmediato (y no toco/verifico la interrupción en ningún otro lado). Echaré un vistazo a UncaughtExceptionHandler. Muchas gracias por su respuesta . (Por cierto, tenga en cuenta este error en Thread.currentThread(). IsInterrupted() http://bugs.sun.com/view_bug.do?bug_id=6772683) – marts

+0

Actualmente, está utilizando correctamente Thread.interrupted() en un de manera segura. Sin embargo, si no necesita el comportamiento proporcionado por ese método, no debería usarlo ya que otra persona (o usted mismo) podría refactorizar ese método de modo que se invoca Thread.interrupted() de manera que invalide el manejo de interrupciones. . Es mucho más seguro usar Thread.currentThread(). IsInterrupted() si puedes. – Kevin

+0

Hola Kevin. Tiene razón, pero debido a un problema con la licencia de Java, no puedo actualizar la JVM actual 1.6.0_02-b05. Me estoy ejecutando en una máquina multiprocesador y mi JVM puede verse afectada por el error que vinculé en el comentario anterior (aquí hay una publicación relacionada en stackoverflow http://stackoverflow.com/questions/2012259/). Acerca de la excepción no controlada, si se trata de un escape de RuntimeException, puedo imaginar que el hilo se muera por sí mismo, ¿no? aquí mi problema es el opuesto ... no se detienen. (o al menos un subconjunto de ellos está detenido) – marts