2010-11-18 22 views
2

J'ai un fichier java jar que j'exécute depuis l'invite de commande Windows. Le code se termine normalement (c'est-à-dire fait ce qu'il est censé faire) mais le processus Java continue de s'exécuter. L'application est à un seul thread. Je dois appuyer sur Ctrl-c pour arrêter le processus une fois le code terminé pour récupérer l'invite de commande.Qu'est-ce qui maintient les processus java en vie après l'exécution du jar?

Je suppose que je pourrais mettre un System.exit(0) à la fin de ma méthode principale qui serait probablement résoudre ce problème, mais j'avais l'impression que ce n'était pas nécessaire. Dans quelles conditions les processus java sont-ils maintenus en vie à la fin de l'exécution? Voici la coquille de ma méthode principale:

public static void main(String[] args) { 
    try { 
     //application code here 
     Logger.log("Now finished"); 
    } catch (SomeExceptoin e) { 
     Logger.error("Some error occured"); 
    } 
} 

Lorsque l'enregistreur est ma propre classe statique incroyablement basique qui dépotoirs juste des messages à System.out.println(). "Now finished" apparaît dans la console, mais le processus continue à s'exécuter. Des idées?

EDIT: Comme demandé, voici le code de l'enregistreur dans toute sa gloire (je ne vous préviens :)

public class Logger { 
    public static void logInfo(String logMessage) 
    { 
     System.out.println(timestamp() + logMessage); 
    } 
    private static String timestamp() 
    { 
     SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd hh:mm:ss"); 
     String timestamp = "[" + formatter.format(new Date()) + "] "; 
     return timestamp; 
    } 
} 

EDIT EDIT: Je mets un bloc finally sur mon essai ci-dessus avec le code de vidage de fil de la lien dans la réponse de instanceofTom. Voici la sortie:

... [2010.11.18 11:22:57] Sortie terminée. Tout le traitement est maintenant terminé.


Nom du thread: Référence gestionnaire java.lang.Object.wait (Native Method) java.lang.Object.wait (Object.java:485) java.lang.ref.Reference $ ReferenceHandler. run (Reference.java:116)


nom du fil: Finalizer java.lang.Object.wait (native Method) java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:116) java .lang.ref.ReferenceQueue.remove (RéférenceQueue.java:132) java.lang.ref.Finalizer $ FinalizerThread.run (Finalizer.java:159)


Nom du fil: Signal Dispatcher


Nom du thread: Joindre Listener


Nom du fil: Java2D Disposer java.lang.Object.wait (Méthode native) java.lang.ref.ReferenceQueue.remove (RéférenceQueue.java:116) java. lang.ref.ReferenceQueue.remove (ReferenceQueue.java:132) sun.java2d.Disposer.run (Disposer.java:125) java.lang.Thread.run (Thread.java:619)


Nom du fil: principal java.lang.Thread.getStackTrace (Thread.java:1436) com.my.code.WorkloadManager.visit (WorkloadManager.java:124) com.my.code.WorkloadManager.visit (WorkloadManager. java: 138) com.my.code.WorkloadManager.main (WorkloadManager.java:71) sun.reflect.NativeMethodAccessorImpl.invoke0 (méthode native) sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:39) sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:25) java.lang.reflect.Method.invoke (Method.java:597) org.eclipse.jdt.internal .jarinjarloader.JarRsrcLoader.main (JarRsrcLoader.java:56)


nom du fil: com.google.inject.internal.Finalizer java.lang.Object.wait (native Method) java.lang.ref .ReferenceQueue.remove (RéférenceQueue.java:116) java.lang.ref.ReferenceQueue.remove (RéférenceQueue.java:132) com.google.inject.internal.Finalizer.run (Finalizer.java:114)


Nom du thread: AWT Windows sun.awt.windows.WToolkit.eventLoop (Native Method) sun.awt.windows.WToolkit.run (WToolkit.java:291) java.lang.Thread .run (Thread.java:619)


nom Sujet: EventQueueMonitor-ComponentEvtDispatch java.lang.Object.wait (native Method) java.lang.Object.wait (Object.java:485) com.sun.java.accessibility.util.ComponentEvtDispatchThread.run (EventQueueMonitor.java:616) * ** * ** * ** * ** * ** * Nom du thread: Référence gestionnaire java.lang.Object.wait (Native Method) java .lang.Object.wait (Object.java:485) java.lang.ref.Reference $ ReferenceHandler.run (Reference.java:116)


nom du fil: Finalizer java.lang.Object.wait (méthode native) java.lang.ref.ReferenceQueue.remove (RéférenceQueue.java:116) java.lang.ref.ReferenceQueue.remove (RéférenceQueue.java:132) java.lang. ref.Finalizer $ FinalizerThread.run (Finalizer.java:159)


nom du fil: signal Dispatcher


nom du thread: Attacher Listener


Nom du fil: Java2D éliminateur java.lang.Object.wait (Native Method) java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:116) java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java: 132) sun.java2d.Disposer.run (Disposer.java:125) java.lang.Thread.run (Thread.java:619)


nom du fil: principal java.lang.Thread. getStackTrace (Thread.java:1436) com.my.code.WorkloadManager.visit (WorkloadManager.java:124) com.my.code.WorkloadManager.visit (WorkloadManager.java:138) com.my.code.WorkloadManager.main (WorkloadManager.java:71) sun.reflect.NativeMethodAccessorImpl.invoke0 (Méthode natif) sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:39) sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java: 25) java.lang.reflect.Method.invoke (Method.java:597) org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main (JarRsrcLoader.java:56)


nom du fil: com.google.inject.internal.Finalizer java.lang.Object.wait (Méthode native) java.lang.ref.ReferenceQueue.remove (RéférenceQueue.java:116) java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:132) com.google.inject.internal.Finalizer.run (Finalizer.java:114)


Nom Sujet: AWT Windows sun.awt.windows.WToolkit.eventLoop (Méthode natif) sun.awt.windows.WToolkit.run (WToolkit.java:291) java.lang.Thread.run (Thread.java:619)


Nom de fil: EventQueueMonitor-ComponentEvtDispatch java.lang.Object.wait (Méthode native) java.lang.Object.wait (Object.java:485) com.sun.java.accessibility.util.ComponentEvtDispatchThread.run (EventQueueMonitor.java:616)

+0

Le programme Java appelle-t-il Runtime.exec() du tout? – izb

+3

Je publierais peut-être aussi le code de l'enregistreur. D'une manière ou d'une autre, un thread orphelin doit persister. Je ne connais pas d'autre moyen pour que cela se produise. – aepryus

+0

Une cause fréquente est d'autres threads non-démon. Bien que votre code soit monothread, êtes-vous certain qu'aucune des choses que vous appelez n'est en train de créer des threads non-démon? –

Répondre

4

Applications Java avec un événement de démarrage de l'interface utilisateur gérant les unités d'exécution qui ne sont pas des unités d'exécution «démon». C'est-à-dire que le programme ne se terminera pas tant que ces threads tourneront — même si aucune fenêtre n'est actuellement affichée.

Avez-vous une commande "Quitter" dans votre menu? Son Action doit appeler System.exit(0).

+0

bonne idée, mais ce n'est pas une application GUI –

+2

@Chris Knight - Votre vidage de thread montre qu'il y a des threads d'événements AWT en cours d'exécution. Il est possible que certaines bibliothèques que vous utilisez utilisent la boîte à outils graphique. Par exemple, j'ai essayé d'utiliser une bibliothèque SVG côté serveur pour générer des images pour une application Web, mais l'application ne fonctionnera pas sur le moteur de l'application Google car elle nécessite des bibliothèques AWT en interne. – erickson

+0

bon point. Je n'avais pas considéré cela. Creuser plus profond J'utilise des bibliothèques JFreeChart pour produire des graphiques qui, par la suite, reçoivent une sortie sur disque, donc pas d'interface utilisateur, mais des bibliothèques graphiques impliquées dans les coulisses. On dirait que c'est ça? –

2

Si tout dans votre code semble normal, il est probable qu'un thread orphelin est toujours en cours d'exécution.

Le code here décrit comment lister tous les threads en cours d'exécution dans la machine virtuelle Java

Sinon, vous pouvez utiliser un profileur ou IDE avec profileur intégré pour afficher les threads en cours d'exécution.

Il serait utile de répondre à cette question si vous pouviez nous faire savoir quels threads sont encore en cours d'exécution lorsque votre code est terminé; Même si votre code peut être monothread il y aura probablement encore d'autres threads en cours d'exécution dans la JVM comme le thread de collecte de place (bien que les threads du GC ne s'arrêteront pas)

+0

Le vidage de threads a été ajouté à ma question en fonction du code de votre lien mis en tant que dernier code exécutable dans ma méthode principale. –

2

Un processus Java restera vivant aussi longtemps car il a un ou plusieurs threads non-démon en cours d'exécution. Envisagez d'utiliser JVisualVM situé dans le répertoire bin du Java JDK et attachez-le à votre programme Java. Là, vous serez en mesure d'effectuer une analyse des threads actifs et de leur état, ainsi que d'effectuer un vidage de thread.

2

Selon votre vidage de fichier, il semble que l'une des bibliothèques Google (peut-être Guice ou Guava) est en cours de chargement.

Thread name: com.google.inject.internal.Finalizer 
java.lang.Object.wait(Native Method) 
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) 
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132) 
com.google.inject.internal.Finalizer.run(Finalizer.java:114) 

Si oui, alors ce bogue pourrait être la cause du problème:

Il est lié au thread finaliseur ne pas laisser aller correctement. Il existe plusieurs solutions de contournement affichées.

+0

cela pourrait aussi être la raison (voir le post d'erickson ci-dessus et les commentaires connexes) que j'utilise Guice pour l'injection de dépendance. Merci. –