2013-02-15 4 views
8

Я хотел попробовать некоторые идеи, используя SwingWorker, так как я не использовал его слишком много. Вместо этого у меня возникла проблема, и я не могу понять, что случилось.Почему SwingWorker неожиданно останавливается?

Вот краткий SSCCE, который демонстрирует эту проблему (я знаю, что люди здесь, как 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; 
    } 
} 

Так что моя программа должна создать 3 SwingWorkers, которые печатают линию на экране, а затем спать в течение указанного количества миллисекунд а затем снова напечатать строку и снова заснуть и т. д. Я создаю SwingWorker s из потока Swing, потому что иначе они даже не начнут.

Таким образом, ожидаемый результат:

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) 
............. 

и так далее в общей сложности 150 линий (3 рабочих х 50 итераций для каждого)

Вместо этого, выход я получаю:

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) 

И все. Всего 3 линии. После этого программа выйдет. Там нет stacktrace от этого блока try catch.

1). Где рабочий со сном 1200 мс? На самом деле, если я заменяю 1200 мс на 1000 мс, тогда этот рабочий также печатает 1 строку ... да, только один. Weird ...

2). Почему рабочие останавливаются? (и я не получаю 150 строк)

Я запустил эту программу, используя JRE 7 Обновление 11 на Windows 7 64-бит.

PS: Я уверен, что the bug mentioned here был исправлен в этой версии JRE, так как я получаю 2 различных значения (15 и 16) в качестве идентификаторов потоков, напечатанных на консоли. Это было первое, что я подозревал.

ответ

9

Я считаю, что вам нужно показать визуализированное окно верхнего уровня Swing, чтобы сохранить поток событий Swing живым. В противном случае программа будет отключена из-за отсутствия потоков не-демона.

Edit:
Чтобы доказать, что SwingWorker нить является Daemon нить, просто добавить строку кода, чтобы проверить:

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 Выполняется ли 'doInBackground'' SwingWorker' в потоке без демона? –

+1

@ Eng.Fouad: посмотрите править. Измените: или посмотрите на источник, как вы это сделали. 1+ к вашему ответу! –

3

Вы пытались создать любой пользовательский интерфейс? или положить что-то вроде new Object().wait(); в конце основного, чтобы предотвратить выход основного потока?

Я не полностью уверен что это так, но без какого-либо фактического отображения пользовательского интерфейса, я уверен, что рабочие-качели - это всего лишь еще один поток, и вы не настроили его как потоки демона, поэтому main запускает их, заканчивает, и процесс выходит?

9

Если вы посмотрите на линии 771 из SwingWorker исходного кода класса (Java SE 7):

thread.setDaemon(true); 

Вы увидите, что SwingWorker выполняется в демона потоке, а в Java виртуальная машина будет прекращена, если все потоки не-демона завершены.

+4

Святое дерьмо, вы, ребята, правы. SwingWorkers работают как потоки демона. Это даже не передумало. Спасибо, StackOverflow, у вас всегда есть ответ на все: D. –

4

Как уже упоминалось, вы можете использовать пользовательский интерфейс, чтобы сохранить потоки живыми.

В качестве альтернативы, вы можете использовать SwingWorker#get (или что-нибудь, что препятствует завершению основного потока), чтобы дождаться окончания потоков. Поступая таким образом, вы получите результат, как ожидалось. Вот модифицированный код, который делает то, что вы хотите.

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

Спасибо, это полезно. –

+0

Очень полезно. 1+ –

+0

Вы заслуживаете +1 :) –

Смежные вопросы