2016-05-05 8 views
2

Ich entwickle eine App, die Tomcat verwendet, um mit einem Raspberry PI zu kommunizieren. Die GUI wird in HTML erstellt und die Kommunikation zwischen diesen beiden wird über Websockets erreicht. So weit, ist es gut.Anhalten von ExecutorService Threads in Tomcat

Ich möchte einen Thread starten, wenn die App zum ersten Mal ausgeführt wird, so dass es eine Reihe von Aufgaben startet. Dies ist ein Test, den ich gemacht habe:

public class ContexService implements ServletContextListener { 

    Thread thread; 
    ExecutorService executorService; 

// ServiceManager serviceManager; 
    @Override 
    public void contextInitialized(ServletContextEvent sce) { 

     System.out.println("-------------> CONTEXT INITIALIZED <-------------"); 
     executorService = Executors.newSingleThreadExecutor(); 
     executorService.submit(new Runnable() { 
      @Override 
      public void run() { 
          Test p = new Test(); 
       int count = 0; 
       while (count < 20) { 
        p.imprimir(count); 
        count++; 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException ex) { 
         System.out.println("error - > " + ex.getMessage()); 
        } 
      } 
     }}); 

} 

    @Override 
    public void contextDestroyed(ServletContextEvent sce) { 

     System.out.println("-------------> CONTEXT DESTROYED <-------------"); 
     if(executorService!=null) 
     { 
      if(!executorService.isShutdown()) 
      { 
       try { 
        executorService.shutdown(); 
        executorService.awaitTermination(3, TimeUnit.SECONDS); 
        if(!executorService.isTerminated()) 
        { 
         executorService.shutdownNow(); 
        } 
       } catch (InterruptedException ex) { 
        Logger.getLogger(ContexService.class.getName()).log(Level.SEVERE, null, ex); 
       } 
      } 
     } 

    } 
} 

Ich betreibe dieses und es funktioniert. Mein Problem ist, dass jedes Mal, wenn ich "play" auf Netbeans drücke, es alles wieder startet (was ich will), aber der Thread mit ExecutorService remaing aktiv gestartet wird. Ich lege die Konsolenausgabe des Katers, damit Sie sehen, was ich meine:

-------------> CONTEXT DESTROYED <------------- 
05-May-2016 15:19:41.668 INFO [http-apr-8080-exec-66] org.apache.catalina.startup.HostConfig.undeploy Repliegue (undeploy) de la aplicación web que tiene como trayectoria de contexto /safemo 
05-May-2016 15:19:41.694 INFO [http-apr-8080-exec-65] org.apache.catalina.startup.HostConfig.deployDescriptor Desplieque del descriptor de configuración C:\apache-tomcat-8.0.33\conf\Catalina\localhost\safemo.xml 
05-May-2016 15:19:42.268 INFO [http-apr-8080-exec-65] org.apache.catalina.startup.HostConfig.deployDescriptor Deployment of configuration descriptor C:\apache-tomcat-8.0.33\conf\Catalina\localhost\safemo.xml has finished in 574 ms 
05-May-2016 15:19:42.273 INFO [http-apr-8080-exec-69] org.apache.catalina.util.LifecycleBase.start The start() method was called on component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/safemo]] after start() had already been called. The second call will be ignored. 
-------------> CONTEXT INITIALIZED <------------- 
15:19:42.446 [pool-4-thread-1] DEBUG sal.Test - 0 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:43.455 [pool-4-thread-1] DEBUG sal.Test - 1 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:44.456 [pool-4-thread-1] DEBUG sal.Test - 2 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:45.456 [pool-4-thread-1] DEBUG sal.Test - 3 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:46.456 [pool-4-thread-1] DEBUG sal.Test - 4 --> TEST <--Thu May 05 15:19:42 CEST 2016 
-------------> CONTEXT DESTROYED <------------- 
15:19:47.456 [pool-4-thread-1] DEBUG sal.Test - 5 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:48.456 [pool-4-thread-1] DEBUG sal.Test - 6 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:49.457 [pool-4-thread-1] DEBUG sal.Test - 7 --> TEST <--Thu May 05 15:19:42 CEST 2016 
error - > sleep interrupted 
15:19:49.484 [pool-4-thread-1] DEBUG sal.Test - 8 --> TEST <--Thu May 05 15:19:42 CEST 2016 
05-May-2016 15:19:49.487 WARNING [http-apr-8080-exec-77] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [safemo] appears to have started a thread named [pool-4-thread-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread: 
java.lang.Thread.sleep(Native Method) 
sal.ContexService$1.run(ContexService.java:42) 
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) 
java.util.concurrent.FutureTask.run(FutureTask.java:266) 
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
java.lang.Thread.run(Thread.java:745) 
05-May-2016 15:19:49.991 INFO [http-apr-8080-exec-77] org.apache.catalina.startup.HostConfig.undeploy Repliegue (undeploy) de la aplicación web que tiene como trayectoria de contexto /safemo 
05-May-2016 15:19:50.034 INFO [http-apr-8080-exec-63] org.apache.catalina.startup.HostConfig.deployDescriptor Desplieque del descriptor de configuración C:\apache-tomcat-8.0.33\conf\Catalina\localhost\safemo.xml 
15:19:50.484 [pool-4-thread-1] DEBUG sal.Test - 9 --> TEST <--Thu May 05 15:19:42 CEST 2016 
05-May-2016 15:19:50.682 INFO [http-apr-8080-exec-63] org.apache.catalina.startup.HostConfig.deployDescriptor Deployment of configuration descriptor C:\apache-tomcat-8.0.33\conf\Catalina\localhost\safemo.xml has finished in 648 ms 
05-May-2016 15:19:50.686 INFO [http-apr-8080-exec-70] org.apache.catalina.util.LifecycleBase.start The start() method was called on component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/safemo]] after start() had already been called. The second call will be ignored. 
-------------> CONTEXT INITIALIZED <------------- 
15:19:50.818 [pool-5-thread-1] DEBUG sal.Test - 0 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:19:51.484 [pool-4-thread-1] DEBUG sal.Test - 10 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:51.824 [pool-5-thread-1] DEBUG sal.Test - 1 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:19:52.485 [pool-4-thread-1] DEBUG sal.Test - 11 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:52.825 [pool-5-thread-1] DEBUG sal.Test - 2 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:19:53.485 [pool-4-thread-1] DEBUG sal.Test - 12 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:53.825 [pool-5-thread-1] DEBUG sal.Test - 3 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:19:54.485 [pool-4-thread-1] DEBUG sal.Test - 13 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:54.825 [pool-5-thread-1] DEBUG sal.Test - 4 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:19:55.486 [pool-4-thread-1] DEBUG sal.Test - 14 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:55.826 [pool-5-thread-1] DEBUG sal.Test - 5 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:19:56.486 [pool-4-thread-1] DEBUG sal.Test - 15 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:56.826 [pool-5-thread-1] DEBUG sal.Test - 6 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:19:57.486 [pool-4-thread-1] DEBUG sal.Test - 16 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:57.826 [pool-5-thread-1] DEBUG sal.Test - 7 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:19:58.486 [pool-4-thread-1] DEBUG sal.Test - 17 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:58.826 [pool-5-thread-1] DEBUG sal.Test - 8 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:19:59.486 [pool-4-thread-1] DEBUG sal.Test - 18 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:19:59.826 [pool-5-thread-1] DEBUG sal.Test - 9 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:20:00.486 [pool-4-thread-1] DEBUG sal.Test - 19 --> TEST <--Thu May 05 15:19:42 CEST 2016 
15:20:00.827 [pool-5-thread-1] DEBUG sal.Test - 10 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:20:01.827 [pool-5-thread-1] DEBUG sal.Test - 11 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:20:02.827 [pool-5-thread-1] DEBUG sal.Test - 12 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:20:03.827 [pool-5-thread-1] DEBUG sal.Test - 13 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:20:04.827 [pool-5-thread-1] DEBUG sal.Test - 14 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:20:05.827 [pool-5-thread-1] DEBUG sal.Test - 15 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:20:06.827 [pool-5-thread-1] DEBUG sal.Test - 16 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:20:07.828 [pool-5-thread-1] DEBUG sal.Test - 17 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:20:08.828 [pool-5-thread-1] DEBUG sal.Test - 18 --> TEST <--Thu May 05 15:19:50 CEST 2016 
15:20:09.828 [pool-5-thread-1] DEBUG sal.Test - 19 --> TEST <--Thu May 05 15:19:50 CEST 2016 

ich die App starten und startet den Druck-Test pool4-Thread 1. ich es wiederzubeleben, und der Faden bleiben zu arbeiten, und ein neuer Thread gestartet (pool5-thread1).

Warum stoppt der Thread nicht, wenn ich "executorService.shutDown" für contextDestroyed ausführe?

Vielen Dank!

+0

Sind Sie sicher, dass der Thread später noch ausgeführt wird? Es kann einige Zeit dauern, bis alles aufhört. Warum haben Sie nicht Ihre "Runnable", um einige Statusinformationen auszudrucken, etwa ob sie noch läuft oder nicht? Ihr Thread benötigt 10 Sekunden, um seine Aufgabe zu erledigen, und Sie beenden Ihre Anwendung ziemlich schnell. Java tötet tatsächlich nur selten Threads, und während der Executor "heruntergefahren" wird, läuft dieser Thread wahrscheinlich noch. –

Antwort

1

Es scheint, wie es zwei Geheimnisse in Ihrer Frage zu lösen:

MYSTERY1: Warum wird es nicht aufhören? Überprüfen Sie Ihre Lauf-Methode: Es wird 20 Mal (von 0 bis 19) Schleife und warten Sie 1 Sekunde jedes Mal, wenn es Schleifen. Also, es wird nicht vor mindestens zwanzig Sekunden getan werden.

Ihr Herunterfahren wartet nur drei Sekunden. Zu dieser Zeit ist deine Arbeit noch nicht erledigt. Sie könnten versuchen, diese Linie zu ersetzen:

executorService.awaitTermination(3, TimeUnit.SECONDS); 

mit diesem:

executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 

Auf diese Weise wird es warten, bis Ihre Aufgabe wirklich fertig ist. HINWEIS: Selbst wenn Sie nicht warten und shutdownNow von Anfang an angerufen haben, würde das auch nicht funktionieren. Dieser Teil des Codes sollte so umgestaltet werden, dass Sie nicht einfach 20 Mal eine Schleife machen, sondern auch überprüfen, ob der Thread unterbrochen ist, während er eine Schleife ausführt, damit er seine Verarbeitung sauber abschließen (kurzschließen) kann. Versuchen Sie, diese Linie zu ändern:

while (count<20) { 

mit dieser:

while (count<20 && !Thread.currentThread().isInterrupted()) { 

sollte diese Lösung erklären helfen, was ich sagte oben: Why ExecutorService.shutdownNow method can't stop the thread Auch lohnt sich, die Dokumentation für shutdownNow lesen: http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html

Es gibt keine Garantien jenseits von Best-Effort-Versuchen, die Ausführung aktiv ausgeführter Aufgaben zu stoppen. Zum Beispiel werden typische Implementierungen über Thread.interrupt() abgebrochen, so dass jede Task, die nicht auf Interrupts reagiert, niemals beendet wird.

MYSTERY2: Warum laufen bei Netbeans die 2 Threads gleichzeitig? Dies liegt wahrscheinlich daran, dass Ihr laufender Thread nie mit der Verarbeitung aufgehört hat und die Unterbrechungsanforderungen nicht bearbeitet. Also, das ist alles zu erwarten, wird Ihr Programm weiter laufen, bis es abgeschlossen ist (Java versucht, Ihren Code zu sagen, um zu stoppen, aber Ihr Code ist derzeit nicht auf diese Nachrichten zu hören).Ja, beide Threads laufen zur gleichen Zeit, wenn Sie das Programm erneut starten (der vorherige Lauf läuft noch und Sie starten einen anderen). Sobald ein Thread die 20. Schleife (Index = 19) erreicht, wird der Thread aufgeräumt und JVM wird hoffentlich endgültig heruntergefahren. Das heißt, es sei denn, Sie in die NetBeans Bug laufen, wo es verlässt JVMs läuft: https://netbeans.org/bugzilla/show_bug.cgi?id=232322

0

Warum ist der Faden nicht zu stoppen, wenn ich „executorService.shutDown“ auf contextDestroyed durchführen?

Herunterfahren ExecutorService wie von Oracle Dokumentationsseite empfohlen.

Ihre Methode sollte

public void contextDestroyed(ServletContextEvent sce) { 

    executorService.shutdown(); // Disable new tasks from being submitted 
     try { 
     // Wait a while for existing tasks to terminate 
     if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) { 
      executorService.shutdownNow(); // Cancel currently executing tasks 
      // Wait a while for tasks to respond to being cancelled 
      if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) 
       System.err.println("executorService did not terminate"); 
     } 
     } catch (InterruptedException ie) { 
     // (Re-)Cancel if current thread also interrupted 
     executorService.shutdownNow(); 
     // Preserve interrupt status 
     Thread.currentThread().interrupt(); 
     } 
} 

shutdown(): Leitet ein ordnungsgemäßes Abschalten ändern, in der zuvor eingereichten Aufgaben ausgeführt werden, aber keine neue Aufgaben akzeptiert werden.

shutdownNow(): Versuche, alle aktiv ausgeführten Tasks zu stoppen, die Verarbeitung wartender Tasks anhalten und eine Liste der Tasks zurückgeben, die auf ihre Ausführung warteten.

können Sie diesen Zustand, wie unten im Fall von längerer Dauer herunterschalten zum Abschalten ExecutorService

Von

if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) 

Um

while (!executorService.awaitTermination(60, TimeUnit.SECONDS)) 
Thread.sleep(60000); 

Wenn Sie Herunterfahren ordnungsgemäß behandeln als je zuvor Code, Sie erhalten möglicherweise keine zweite Ausgabe in mehreren ExecutorService Pools.

Verwandte Themen