2010-05-12 21 views
10

Estoy intentando usar futuros por primera vez. Parece inteligente que puede cancelar un trabajo, pero no está funcionando como se esperaba. En el siguiente ejemplo, solo se cancela el primer trabajo. El resto está completo. ¿He entendido mal el uso de futuros?Comprender el futuro/subprocesamiento

public class ThreadExample 
{ 
    public static void main(String[] args) throws InterruptedException, ExecutionException 
    { 
     int processors = Runtime.getRuntime().availableProcessors(); 
     System.out.println("Processors: " + processors); 
     ExecutorService es = Executors.newFixedThreadPool(processors); 
     int nowork = 10; 
     Future<Integer>[] workres = new Future[nowork]; 
     for(int i = 0; i < nowork; i++) 
     { 
      workres[i] = es.submit(new SomeWork(i)); 
     } 
     for(int i = 0; i < nowork; i++) 
     { 
      if(i % 2 == 0) 
      { 
       System.out.println("Cancel"); 
       workres[i].cancel(true); 
      } 
      if(workres[i].isCancelled()) 
      { 
       System.out.println(workres[i] + " is cancelled"); 
      } 
      else 
      { 
       System.out.println(workres[i].get()); 
      } 
     } 
     es.shutdown(); 
    } 
} 

class SomeWork implements Callable<Integer> 
{ 
    private int v; 
    public SomeWork(int v) 
    { 
     this.v = v; 
    } 

    @Override 
    public Integer call() throws Exception 
    { 
     TimeUnit.SECONDS.sleep(5); 
     System.out.println(v + " done at " + (new Date())); 
     return v; 
    } 
} 

La salida:

Processors: 4 
Cancel 
[email protected] is cancelled 
4 done at Wed May 12 17:47:05 CEST 2010 
2 done at Wed May 12 17:47:05 CEST 2010 
1 done at Wed May 12 17:47:05 CEST 2010 
3 done at Wed May 12 17:47:05 CEST 2010 
1 
Cancel 
2 
3 
Cancel 
4 
5 done at Wed May 12 17:47:10 CEST 2010 
7 done at Wed May 12 17:47:10 CEST 2010 
8 done at Wed May 12 17:47:10 CEST 2010 
6 done at Wed May 12 17:47:10 CEST 2010 
5 
Cancel 
6 
7 
Cancel 
8 
9 done at Wed May 12 17:47:15 CEST 2010 
9 

Respuesta

7

El problema es que su bucle de cancelación se superpone con su bucle get(), que bloquea. Creo que quieres tener 2 bucles, ¿no? Un bucle que cancela los trabajos con números pares, y luego un segundo bucle que verifica cuáles se cancelan y cuáles no, y luego get() en consecuencia.

La forma en que está escrito ahora, antes de que el ciclo tuviera la oportunidad de cancelar workres[2], comprobó y solicitó get() desde workres[1].

Así que creo que necesita 3 fases:

1. The `submit()` loop 
2. The selective `cancel()` loop 
3. The selective `get()` loop (which blocks) 
+0

¡Gracias! No pensé en get() como un método que bloquea un problema. –

8

El Future#cancel() no terminará/interrumpir el ya se está ejecutando puestos de trabajo. Solo cancelará los trabajos que aún no se ejecutan.

actualización: polygenelubricants clavó la causa raíz hacia abajo (1): aquí está el código mejorada:

int processors = Runtime.getRuntime().availableProcessors(); 
System.out.println("Processors: " + processors); 
ExecutorService es = Executors.newFixedThreadPool(processors); 
int nowork = 10; 
Future<Integer>[] workers = new Future[nowork]; 

for (int i = 0; i < nowork; i++) { 
    final int ii = i; 
    workers[i] = es.submit(new Callable<Integer>() { 
     public Integer call() throws Exception { 
      return ii; 
     } 
    }); 
} 

for (int i = 0; i < nowork; i++) { 
    if (i % 2 == 0) { 
     System.out.println("Cancel worker " + i); 
     workers[i].cancel(true); 
    } 
} 

for (int i = 0; i < nowork; i++) { 
    if (workers[i].isCancelled()) { 
     System.out.println("Worker " + i + " is cancelled"); 
    } else { 
     System.out.println("Worker " + i + " returned: " + workers[i].get()); 
    } 
} 

es.shutdown(); 

Resultado:

 
Processors: 2 
Cancel worker 0 
Cancel worker 2 
Cancel worker 4 
Cancel worker 6 
Cancel worker 8 
Worker 0 is cancelled 
Worker 1 returned: 1 
Worker 2 is cancelled 
Worker 3 returned: 3 
Worker 4 is cancelled 
Worker 5 returned: 5 
Worker 6 is cancelled 
Worker 7 returned: 7 
Worker 8 is cancelled 
Worker 9 returned: 9 

(tenga en cuenta que se trata de workers, no workres) .

+0

"Si la tarea ya ha comenzado, entonces el parámetro mayInterruptIfRunning determina si el hilo de ejecutar esta tarea debe ser interrumpido en un intento de detener la tarea." Imo cancel es una palabra/methodname muy malo para usar si solo puedes usarlo en trabajos que todavía no se ejecutan:/ –

+0

Yo mismo encuentro la diferencia entre 'cancel' y' interrupt' (o 'abort' or' terminate') aún lo suficientemente claro. – BalusC

+0

Puede llamar a '.cancel (true)' para forzar un trabajo que ha comenzado a interrumpirse. – Finbarr