2012-08-11 13 views
10

Gibt es eine Möglichkeit, ExecutorService zu verwenden, um einen bestimmten Thread anzuhalten/fortzusetzen?Java ExecutorService einen bestimmten Thread pausieren/fortsetzen

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

vorstellen, dass ich den Faden wich als ID = 0 (unter der Annahme, dass zu jeder eine inkrementelle ID, bis die Größe des Threadpool zugeordnet ist, wird erreicht) gestoppt werden soll.

Nach einer Weile, sagen wir, indem ich einen Knopf drücke, möchte ich diesen bestimmten Thread fortsetzen und alle anderen Threads mit ihrem aktuellen Status belassen, der pausiert oder fortgesetzt werden kann.

Ich habe auf Java-Dokumentation eine unvollständige Version von PausableThreadPoolExecutor gefunden. Aber es passt nicht, was ich brauche, weil es alle Threads im Pool wieder aufnimmt.

Wenn es keine Möglichkeit gibt, es mit der Standardimplementierung des ExecutorService zu tun, kann mich jemand auf eine Java-Implementierung für dieses Problem hinweisen?

Danke!

+0

Sind Sie sicher?Thread mit der angegebenen ID führt einen zufällig ausgewählten Job aus, sodass Sie einen unbekannten Job stoppen. Was macht der Sinn? –

+0

Stellen Sie sich die folgende Situation vor: Sie haben einen Download-Manager, und auf diesem Manager können Sie Downloads anhalten und fortsetzen. Für jeden, den Sie herunterladen, spielt es keine Rolle, was nicht relevant ist, und Sie möchten verhindern, dass der Download wieder aufgenommen wird, wo immer Sie möchten. Macht dies die Frage für Sie klarer? –

+0

Klarer, aber immer noch nicht viel Sinn. Beim Stoppen/Fortsetzen von Downloads geht es um Geschäftslogik, beim Threadpool geht es um Rechenressourcen. Logik durch Hinzufügen/Entfernen von Ressourcen zu steuern ist eine schlechte Idee IMHO. –

Antwort

7

Sie sind auf der falschen Spur. Der Thread-Pool besitzt die Threads, und wenn Sie sie mit Ihrem Code teilen, kann dies zu Problemen führen.
Sie sollten sich auf konzentrieren, damit Ihre Aufgaben (an die Threads abbrechbar/unterbrechbar übergeben) und nicht mit den Threads im Besitz des Pools direkt interagieren.
Zusätzlich würden Sie nicht wissen, welche Arbeit zu dem Zeitpunkt ausgeführt wird, Sie versuchen, den Thread zu unterbrechen, so kann ich nicht sehen, warum Sie dabei diese

aktualisieren interessieren:
Der richtige Weg zu Abbrechen Ihre Aufgabe im Thread-Pool eingereicht wird über die Future für die Aufgabe vom Executor zurückgegeben.
1) Auf diese Weise können Sie sicher wissen, dass die Aufgabe, die Sie tatsächlich zielen darauf versucht wird
2 abgebrochen werden) Wenn Sie Ihre Aufgaben bereits kündbar sein sollen, dann sind Ihre halbem Weg gibt
3) Verwenden Sie kein Flag verwenden Stornierung, um anzuzeigen, sondern verwenden Thread.currentThread().interrupt() statt

Update:

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

Können Sie genauer sein und mir eine echte Implementierung oder ein Beispiel geben? Das habe ich sehr geschätzt, denn ich kämpfe ziemlich lange mit diesem Problem. –

+0

@RicardoSantos: Aber warum machen Sie Ihre Aufgaben nicht abbrechbar? Es ist keine gute Idee, mit Threads zu interagieren, die Ihr Code nicht direkt besitzt. – Cratylus

+0

Ich stimme der Empfehlung zu, Aufgaben kündbar zu machen. Das OP schrieb "Stell dir vor, ich möchte Thread-ID = 0 stoppen". Das macht nicht viel Sinn, weil Sie zu einem bestimmten Zeitpunkt nicht wissen, was Thread 0 tut. Aber es macht Sinn, über das Stoppen einiger Arbeiten zu sprechen, daher die Empfehlung, Aufgaben abzubrechen. –

4

Vorschlag: Ähnlich/anstelle der Flags verwenden Sie, erstellen Sie eine semaphore mit 1 Genehmigung (new Semaphore(1)) fo r jede Aufgabe, die Sie anhalten/fortsetzen müssen. Zu Beginn des Arbeitszyklus der Aufgabe stellen einen Code wie folgt aus:

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

Diese Aufgabe führt zu einer Semaphore Erlaubnis zum Erwerb und sofort loslassen. Wenn Sie nun den Thread pausieren möchten (z. B. eine Taste), rufen Sie semaphore.acquire() von einem anderen Thread auf. Da der Semaphor jetzt 0 Genehmigungen hat, pausiert Ihr Arbeits-Thread zu Beginn des nächsten Zyklus und wartet, bis Sie semaphore.release() von dem anderen Thread aufrufen.

(Die acquire() Methode wirft InterruptedException, wenn Ihr Arbeitsfaden während des Wartens unterbrochen wird. Es ist eine weitere Methode acquireUninterruptibly(), die auch eine Genehmigung zu erwerben versucht, aber nicht unterbrochen bekommen.)

+0

Sicher macht es den Job aber klingt eher nach einem Hack und es ist ein besserer Ansatz als nichts zu tun. Also danke für deine Antwort. Ich werde Ihren Ansatz und @ user384706 testen und sehen, welcher eine bessere Leistung hat. –

Verwandte Themen