2012-08-11 25 views
10

¿Hay alguna manera de utilizar ExecutorService para pausar/reanudar un hilo específico?Java ExecutorService pausa/reanudar un hilo específico

private static ExecutorService threadpool = Executors.newFixedThreadPool(5);

Imagínese que quiero detener el wich hilo como el id = 0 (suponiendo que a cada uno se le asigna un ID incrementales hasta que el tamaño de la threadpool se alcanza).

Después de un tiempo, al presionar un botón digamos, quiero reanudar ese hilo específico y dejar todos los otros hilos con su estado actual, que puede pausarse o reanudarse.

He encontrado en la documentación de Java una versión incompleta de PausableThreadPoolExecutor. Pero no se ajusta a lo que necesito porque reanuda todos los hilos en el conjunto.

Si no hay forma de hacerlo con la implementación predeterminada del ExecutorService ¿alguien me puede indicar una implementación de Java para este problema?

Gracias!

+0

¿Seguro?El subproceso con id. Dado ejecuta un trabajo elegido al azar, por lo que está deteniendo un trabajo desconocido. ¿Qué sentido tiene hacerlo? –

+0

Imagine la siguiente situación: tiene un administrador de descargas y en ese administrador puede detener y reanudar las descargas. Para cada uno de ellos está descargando cosas, no importa lo que no sea relevante, y desea evitar que la descarga se reanude donde lo desee. ¿Esto hace que la pregunta sea más clara para ti? –

+0

Más claro, pero aún no tiene mucho sentido. Detener/reanudar descargas tiene que ver con la lógica empresarial, mientras que el hilo de rosca se trata de recursos computacionales. Para controlar la lógica por agregar/eliminar recursos es una mala idea en mi humilde opinión. –

Respuesta

7

Estás en el camino equivocado. El grupo de subprocesos posee los subprocesos y al compartirlos con su código podría estropear las cosas.
Debería centrarse en realizando sus tareas (pasadas a los hilos cancelables/interrumpibles) y no interactuar directamente con los subprocesos propiedad del grupo.
Además no sabría qué trabajo se está ejecutando en el momento de intentar interrumpir el hilo, por lo que no se puede ver por qué está interesado en hacer esto

Actualización:
La forma correcta de cancele su tarea enviada en el grupo de subprocesos a través del Future para la tarea devuelta por el ejecutor.
1) Este modo se puede saber a ciencia cierta si la tarea que en realidad apunta a que se intente que ser cancelado
2) Si sus tareas ya están diseñados para ser canceladas después su esté a mitad de camino
3) No utilice una bandera para indicar la cancelación pero el uso de Thread.currentThread().interrupt() lugar

actualización:

public class InterruptableTasks { 

    private static class InterruptableTask implements Runnable{ 
     Object o = new Object(); 
     private volatile boolean suspended = false; 

     public void suspend(){   
      suspended = true; 
     } 

     public void resume(){  
      suspended = false; 
      synchronized (o) { 
       o.notifyAll(); 
      } 
     } 


     @Override 
     public void run() { 

      while(!Thread.currentThread().isInterrupted()){ 
       if(!suspended){ 
        //Do work here  
       } 
       else{ 
        //Has been suspended 
        try {     
         while(suspended){ 
          synchronized(o){ 
           o.wait(); 
          }       
         }      
        } 
        catch (InterruptedException e) {      
        }    
       }       
      } 
      System.out.println("Cancelled");   
     } 

    } 

    /** 
    * @param args 
    * @throws InterruptedException 
    */ 
    public static void main(String[] args) throws InterruptedException { 
     ExecutorService threadPool = Executors.newCachedThreadPool(); 
     InterruptableTask task = new InterruptableTask(); 
     Map<Integer, InterruptableTask> tasks = new HashMap<Integer, InterruptableTask>(); 
     tasks.put(1, task); 
     //add the tasks and their ids 

     Future<?> f = threadPool.submit(task); 
     TimeUnit.SECONDS.sleep(2); 
     InterruptableTask theTask = tasks.get(1);//get task by id 
     theTask.suspend(); 
     TimeUnit.SECONDS.sleep(2); 
     theTask.resume(); 
     TimeUnit.SECONDS.sleep(4);     
     threadPool.shutdownNow();  
    } 
+0

¿Puede ser más específico y proporcionarme una implementación real o un ejemplo? Realmente lo aprecié, porque estoy luchando con este problema desde hace mucho tiempo. –

+0

@RicardoSantos: ¿Pero por qué no cancelas tus tareas? No es una buena idea interactuar con hilos que tu código no posee directamente – Cratylus

+0

Estoy de acuerdo con la recomendación de hacer las tareas cancelables. El OP escribió "imagine que quiero detener el id del hilo = 0". Esto no tiene mucho sentido, porque en un momento dado no sabes qué hilo 0 está haciendo. Pero tiene sentido hablar de detener el trabajo que se está realizando actualmente, de ahí la recomendación de cancelar tareas. –

4

Sugerencia: de manera similar a/en lugar de las banderas que está utilizando, cree un permiso semaphore con 1 (new Semaphore(1)) fo En cada tarea que necesita para pausar/reanudar. Al principio del ciclo de trabajo de la tarea poner un código como el siguiente:

semaphore.acquire(); 
semaphore.release(); 

Esto hace que la tarea de adquirir un permiso de semáforos e inmediatamente soltarlo. Ahora, si quiere pausar el hilo (por ejemplo, se presiona un botón), llame al semaphore.acquire() desde otro hilo. Dado que el semáforo tiene 0 permisos ahora, su hilo de trabajo se detendrá al comienzo del próximo ciclo y esperará hasta que llame al semaphore.release() del otro hilo.

(El método acquire() lanza InterruptedException, si el hilo de trabajo se interrumpe mientras espera. Hay otro método acquireUninterruptibly(), que también intenta adquirir un permiso, pero no consigue interrumpido.)

+0

Claro que hace el trabajo, pero suena más como un truco y es un mejor enfoque que no hacer nada. Así que gracias por responder. Voy a probar tu enfoque y @ user384706 y ver cuál tiene un mejor rendimiento. –

Cuestiones relacionadas