2010-09-23 23 views
6

Ich schreibe eine Anwendung, die mehrere gleichzeitige Aufgaben hervorbringt. Ich verwende einen Thread-Pool, um das zu implementieren.Wie man einen Thread in einem Threadpool stoppt

Es kann vorkommen, dass ein Ereignis auftritt, macht die Berechnungen ungültig in den Aufgaben erledigt werden. In diesem Fall möchte ich die laufenden Aufgaben stoppen und neue starten.

Mein Problem: Wie stoppe ich die laufenden Aufgaben? Die von mir implementierte Lösung besteht darin, einen Verweis auf den Task-Thread zu speichern und interrupt() für diesen Thread aufzurufen. Im Demo-Code:

public class Task implements Runnable { 

    private String name; 
    private Thread runThread; 

    public Task(String name) { 
     super(); 
     this.name = name; 
    } 

    @Override 
    public void run() { 
     runThread = Thread.currentThread(); 

     System.out.println("Starting thread " + name); 
     while (true) { 
      try { 
       Thread.sleep(4000); 
       System.out.println("Hello from thread " + name); 
      } catch (InterruptedException e) { 
       // We've been interrupted: no more messages. 
       return; 
      } 
     } 
    } 

    public void stop() { 
     runThread.interrupt(); 
    } 

    public String getName() { 
     return name; 
    } 
} 

Und die wichtigste Methode ist:

public static void main(String args[]) { 
    executorService = Executors.newFixedThreadPool(2); 

    Task t1 = new Task("Task1"); 
    Task t2 = new Task("Task2"); 
    executorService.execute(t1); 
    executorService.execute(t2); 
    executorService.execute(new Task("Task3")); 
    executorService.execute(new Task("Task4")); 

    try { 
     Thread.sleep(12000); 
     t1.stop(); 
     System.err.println("Stopped thread " + t1.getName()); 
     Thread.sleep(8000); 
     t2.stop(); 
     System.err.println("Stopped thread " + t2.getName()); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 

Ist dies eine gute Lösung, oder gibt es einen besseren Weg, um einen laufenden Thread in einem Thread-Pool zu stoppen?

+1

Ziehen Sie den Stecker;) – sje397

Antwort

2

In Ihrer überschrieben run() Methode Sie Schleife für immer mit while(true). Das Standardverhalten wäre, eine boolean runIndicator zu haben, die die run()-Methode auf True setzt, wenn es gestartet wird, und Ihre Schleife sollte dann while(runIndicator) sein. Ihre stop() Methode sollte einfach runIndicator = false setzen, damit die nächste Iteration der Schleife ausfallen wird.

+0

In dieser Implementierung sollte die 'stop()' Methode auch 'this.interrupt()' aufrufen. In der tatsächlichen Implementierung sollte es eine ähnliche Methode geben, die Sie verwenden können, um zu stoppen, was auch immer schweres Heben statt des 'Thread.sleep * (4000)' Aufrufs ist. Sie können eine sehr ähnliche Methode zum 'runIndicator' verwenden, um dies zu erreichen. –

+0

@Erick, 'interrupt()' ist keine Methode von Runnable, das ist also nicht möglich. 'Thread.currentThread(). Interrupt()' würde nicht funktionieren, weil der Aufruf von stop() in einem anderen Thread als dem auftritt, den Sie unterbrechen möchten. – Thirler

+1

Sorry, ich habe das nicht verstanden. Ich erweitere immer 'Thread' statt' Runnable', so dass ich immer Zugriff auf diese Dinge habe. Ich würde das gleiche hier tun. Dies würde auch das Problem lösen, das Sie in Ihrer Antwort angegeben haben. –

3

Die Idee hinter Ihrem Ansatz ist eine der richtigen Lösungen. Dealing with InterruptedException gibt einen guten Überblick darüber, wie Sie den Interrupt-Mechanismus verwenden sollten. Dieser Mechanismus ist hauptsächlich nützlich, wenn Sie lange Berechnungen durchführen. Eine andere Sache zu beachten ist, dass es für andere Bibliotheken möglich ist, Ihren Interrupt-Mechanismus zu stören, indem Sie nicht tun, was der Guide sagt (den Interrupt-Zustand nicht zurücksetzen, wenn sie ihn nicht behandelt haben usw.).

Sie beachten Sie, dass Ihre Task Klasse nicht Thread-sicher ist. Sie könnten die Aufgabe stoppen, bevor Sie die currentThread speichern, die eine NullPointerException ergeben würde.

ist eine einfachere Alternative ist eine volatile boolean Variable running und anstelle einer while(true) Schleife setzen einen while(running) Ansatz tun (dies jedoch viel allgemeiner ist).

Eine andere Sache zu betrachten ist die FutureTask Mechanismus, wie dies bereits einen Aufhebungsmechanismus hat, der den Interrupt-Mechanismus verwendet.

1

executorService.shutdown() und executorService.shutdownNow() soll den Faden-Pool zum Herunterfahren verwendet werden, um die Anwendung zu ordnungsgemäß verlassen. Siehe ExecutorService.

Siehe Qwerkys Antwort zum Beenden des aktuell laufenden Threads.

+4

Er möchte einen einzelnen Thread herunterfahren, nicht den ganzen Pool. –

+0

Diese Antwort wird von Qwerky gegeben. Aber das Herunterfahren des Thread-Pools ist auch erforderlich, um die Anwendung ordnungsgemäß zu beenden. –

2

Sie können es stoppen, indem Sie einen Verweis auf diese Zukunft hält

  Future<?> future = exec.submit(new Runnable() { 
     while (true){ 
     try{ 
      obj.wait(); 
     }catch(InterruptedException e){ 
      System.out.println("interrupted"); 
      return; 
     } 
     }); 
     future.cancel(true); 

boolean ist - wenn bei der Ausführung unterbrechen kann.

testete ich und bekam eine unterbrochene Ausnahme von diesem Thread.

Wenn Sie cachedThreadPool haben Sie wollen möglicherweise verdoppeln überprüfen, dass Sie die Ausnahme in der runnable fangen, und dann wird das Flag unterbrochen nicht zurückgesetzt, weil der Thread eine andere Zukunft laufen wird, wenn Sie unterbrechen gesetzt, die andere Warteschlange Zukunft darf nicht laufen.

Verwandte Themen