2013-02-15 3 views
8

Ich wollte einige Ideen mit SwingWorker ausprobieren, da ich es nicht zu viel benutzt habe. Stattdessen stieß ich auf ein Problem und ich kann nicht herausfinden, was falsch ist.Warum stoppt SwingWorker unerwartet?

Hier ein kurzes SSCCE, die dieses Problem veranschaulicht (Ich weiß, die Leute hier wie SSCCEs):

import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 

public class SwingWorkerTest 
{ 
    public static void main (String[] args) 
    { 
     SwingUtilities.invokeLater (new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       new MySwingWorker (500).execute(); 
       new MySwingWorker (900).execute(); 
       new MySwingWorker (1200).execute(); 
      } 
     }); 
    } 
} 

class MySwingWorker extends SwingWorker<Void, Void> 
{ 
    private int ms; 

    public MySwingWorker (int ms) 
    { 
     this.ms = ms; 
    } 

    @Override 
    protected Void doInBackground() 
    { 
     Thread t = Thread.currentThread(); 

     for (int i = 0; i < 50; i++) 
     { 
      try 
      { 
       Thread.sleep (ms); 
      } 
      catch (InterruptedException e) 
      { 
       e.printStackTrace(); 
      } 

      System.out.println ("I am thread with " + ms + " sleep in iteration " + i + ": " + t.getName() + " (" + t.getId() + ")"); 
     } 

     return null; 
    } 
} 

Also mein Programm soll 3 SwingWorkers erstellen, die eine Linie auf dem Bildschirm gedruckt werden dann für die angegebene Anzahl von Millisekunden schlafen und dann die Zeile wieder ausdrucken und wieder schlafen usw. Ich erstelle die SwingWorker s aus dem Thread von Swing, weil sie sonst nicht einmal starten würden.

So ist die erwartete Ausgabe ist:

I am thread with 500 sleep in iteration 0: SwingWorker-pool-1-thread-1 (15) 
I am thread with 900 sleep in iteration 0: SwingWorker-pool-1-thread-2 (16) 
I am thread with 500 sleep in iteration 1: SwingWorker-pool-1-thread-1 (15) 
I am thread with 1200 sleep in iteration 0: SwingWorker-pool-1-thread-3 (17) 
I am thread with 500 sleep in iteration 2: SwingWorker-pool-1-thread-1 (15) 
I am thread with 900 sleep in iteration 1: SwingWorker-pool-1-thread-2 (16) 
I am thread with 500 sleep in iteration 3: SwingWorker-pool-1-thread-1 (15) 
I am thread with 1200 sleep in iteration 1: SwingWorker-pool-1-thread-3 (17) 
I am thread with 500 sleep in iteration 4: SwingWorker-pool-1-thread-1 (15) 
I am thread with 900 sleep in iteration 2: SwingWorker-pool-1-thread-2 (16) 
I am thread with 500 sleep in iteration 5: SwingWorker-pool-1-thread-1 (15) 
I am thread with 500 sleep in iteration 6: SwingWorker-pool-1-thread-1 (15) 
I am thread with 900 sleep in iteration 3: SwingWorker-pool-1-thread-2 (16) 
I am thread with 1200 sleep in iteration 2: SwingWorker-pool-1-thread-3 (17) 
I am thread with 500 sleep in iteration 7: SwingWorker-pool-1-thread-1 (15) 
............. 

und so weiter für insgesamt 150 Zeilen (3 Arbeiter x 50 Wiederholungen für jeden)

Stattdessen wird der Ausgang I erhalten ist:

I am thread with 500 sleep in iteration 0: SwingWorker-pool-1-thread-1 (15) 
I am thread with 900 sleep in iteration 0: SwingWorker-pool-1-thread-2 (16) 
I am thread with 500 sleep in iteration 1: SwingWorker-pool-1-thread-1 (15) 

Und das ist es. Nur 3 Zeilen. Danach wird das Programm beendet. Es gibt keinen StackTrace irgendwo von diesem try catch Block.

1). Wo ist der Arbeiter mit den 1200ms Schlaf? Wenn ich 1200ms durch 1000ms ersetze, dann druckt dieser Arbeiter auch 1 Zeile ... ja, nur einen. Weird ...

2). Warum hören die Arbeiter auf? (und ich bekomme nicht 150 Zeilen Zeug)

Ich lief dieses Programm mit JRE 7 Update 11 auf Windows 7 64-Bit.

PS: Ich bin mir ziemlich sicher, dass the bug mentioned here in dieser Version von JRE behoben wurde, da ich 2 verschiedene Werte (15 und 16) als Thread-IDs auf der Konsole gedruckt bekommen. Das war das erste, was ich vermutete.

Antwort

9

Ich glaube, dass Sie ein visualisiertes Swing-Top-Level-Fenster anzeigen müssen, um den Swing-Ereignis-Thread lebendig zu halten. Andernfalls wird das Programm wegen fehlender Nicht-Daemon-Threads heruntergefahren.

Edit:
Um zu beweisen, dass der Swingworker Thread ein Daemon-Thread ist, fügen Sie einfach eine Zeile Code zu testen:

System.out.println("I am thread with " + ms + " sleep in iteration " 
    + i + ": " + t.getName() + " (" + t.getId() + ")"); 

// **** added 
System.out.println("Daemon?: " + Thread.currentThread().isDaemon()); 
+0

+1 Wird "doInBackground" von 'SwingWorker' in einem Nicht-Daemon-Thread ausgeführt? –

+1

@ Eng.Fouad: bitte schauen Sie auf Bearbeiten. Bearbeiten: oder sehen Sie sich die Quelle an, wie Sie es getan haben. 1+ zu deiner Antwort! –

3

Haben Sie versucht, jede UI zu erstellen? oder am Ende von main etwas wie new Object().wait(); setzen, um zu verhindern, dass der Hauptfaden austritt?

Ich bin nicht ganz sicher, dass dies der Fall ist, aber ohne tatsächliche Benutzeroberfläche zeigt, bin ich ziemlich sicher, die Swing Worker sind nur ein weiterer Thread, und Sie haben keine als Daemon-Threads konfiguriert, so main startet sie, Haupt beendet, und der Prozess endet?

9

Wenn Sie an der Linie sehen 771 Swingworker Klasse Quellcode (Java SE 7):

thread.setDaemon(true); 

Sie werden sehen, dass die SwingWorker innerhalb eines Daemon-Thread ausgeführt wird, und in Java wird die JVM beendet werden, wenn Alle Nicht-Daemon-Threads sind beendet.

+4

Heiliger Mist, ihr habt Recht. SwingWorker laufen als Daemon-Threads. Das kam mir nicht einmal in den Sinn. Danke, StackOverflow, du hast immer die Antwort auf alles: D. –

4

Wie bereits erwähnt, können Sie die Benutzeroberfläche verwenden, um die Threads am Leben zu erhalten.

Alternativ können Sie SwingWorker#get (oder irgendetwas, das verhindert, dass der Haupt-Thread beendet) auf das Ende der Threads warten. Auf diese Weise erhalten Sie die Ausgabe wie erwartet. Hier ist der modifizierte Code, der das macht, was Sie wollen.

import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 
import java.util.concurrent.ExecutionException; 

public class SwingWorkerTest 
{ 
    public static void main (String[] args) 
    { 
     final MySwingWorker w1 = new MySwingWorker (500), 
     w2 = new MySwingWorker (900), 
     w3 = new MySwingWorker (1200); 
     SwingUtilities.invokeLater (new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       w1.execute(); 
       w2.execute(); 
       w3.execute(); 
      } 
     }); 

     try{ 
      // you can replace the code in this block 
      // by anything that keeps the program from 
      // terminating before the threads/SwingWorkers. 
      w1.get(); 
      w2.get(); 
      w3.get(); 
     }catch(InterruptedException e){ 
      System.err.println("InterruptedException occured"); 
     }catch(ExecutionException e){ 
      System.err.println("InterruptedException occured"); 
     } 

    } 
} 

class MySwingWorker extends SwingWorker<Void, Void> 
{ 
    private int ms; 

    public MySwingWorker (int ms) 
    { 
     this.ms = ms; 
    } 

    @Override 
    protected Void doInBackground() 
    { 
     Thread t = Thread.currentThread(); 

     for (int i = 0; i < 50; i++) 
     { 
      try 
      { 
       Thread.sleep (ms); 
      } 
      catch (InterruptedException e) 
      { 
       e.printStackTrace(); 
      } 

      System.out.println ("I am thread with " + ms + " sleep in iteration " + i + ": " + t.getName() + " (" + t.getId() + ")"); 
     } 

     return null; 
    } 
} 
+0

Danke, das ist hilfreich. –

+0

Sehr hilfreich in der Tat. 1+ –

+0

Du verdienst +1 :) –