4

事情是這樣的:我有一個Java應用程序主窗口的JFrame,它包含一個帶有多個JProgressBar的面板。我想爲每個JProgressBar啓動一個Thread,它將自己啓動另一個Threads。當這些「次要」線程完成時,我想更新我的JFrame中的JProgressBar。此外,在安排所有這些之前,因爲我不希望用戶能夠點擊JFrame上的任何內容,我還想在JFrame中設置一些(false)一些按鈕。簡單?JFrame調用多個併發線程來更新調用者JFrame中的JProgressBar

ActivarBotones abFalse = new ActivarBotones(false); 
abFalse.start(); 
try { 
    abFalse.join(); 
} catch (InterruptedException e1) { 
    // TODO Auto-generated catch block 
    e1.printStackTrace(); 
} 

EstablecerConexiones ec = new EstablecerConexiones(); 
ec.start(); 
try { 
    ec.join(); 
} catch (InterruptedException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} 

ActivarBotones abTrue = new ActivarBotones(true); 
abTrue.start(); 

兩個問題。

  1. 如果我從上面運行的代碼,沒有得到更新。如果我只啓動ec線程,那麼一切都很正常。

  2. 我對同步瞭解不多,不知道該怎麼做才能同時啓動所有「主」線程。

任何線索?

+0

當您從其他線程更新JProgressBar時,是從AWT EventQueue線程內部調用它們嗎? –

回答

1

ActivarBotones線程未完成。

如果它在你沒有運行該線程的情況下有效,那麼該線程中的某些東西沒有完成。否則,它將進入EstablecerConexiones線程。由於您在啓動該線程後致電.join(),代碼將不會繼續,直到該線程完成。所以那裏一定有東西阻塞或陷入循環。

以調試模式運行您的應用程序,並在ActivarBotones線程中放置一個斷點。通過它跟蹤,看看它爲什麼沒有完成。

對於第二個問題,如果您啓動每個主線程但不加入它們,直到它們全部啓動,它們將全部同時運行。當然,這太過簡單化了。許多人更喜歡使用執行者服務來控制他們的線程。你也必須擔心線程安全的實現,所以你不會遇到同步問題。最後,如果你正在與Swing組件交互,那麼所有這些都需要在專用的Event Dispatch Thread上完成。

+0

謝謝你的回答,埃裏克。 當我說「沒有更新的東西」時,我應該補充說,「除了其他所有事情都做得很好」。就是這樣,我認爲我在更新和美國東部時間有問題。用它做事的正確方法是什麼? 而且,我會尋找執行者服務,你知道我在哪裏可以看到關於它的一些信息嗎? – gobispo

2

這裏有一個小樣本,我不認爲它回答你所有的問題,但它表明了基本概念(有一個生病的妻子&照顧6個月大的,用一隻手打字:P)

public class ThreadedProgress { 

    public static void main(String[] args) { 
     new ThreadedProgress(); 
    } 

    public ThreadedProgress() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException ex) { 
       } catch (InstantiationException ex) { 
       } catch (IllegalAccessException ex) { 
       } catch (UnsupportedLookAndFeelException ex) { 
       } 

       JPanel progressPane = new JPanel(new GridBagLayout()); 
       JProgressBar progressBar = new JProgressBar(0, 100); 
       progressPane.add(progressBar); 

       JFrame frame = new JFrame(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(progressPane); 
       frame.setSize(200, 200); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 

       new Thread(new MainThread(progressBar)).start(); 

      } 

     }); 
    } 

    public interface CallBack { 
     public void done(Runnable runnable); 
    } 

    public static class MainThread implements CallBack, Runnable { 

     public static final Object UPDATE_LOCK = new Object(); 
     public static final Object WAIT_LOCK = new Object(); 
     private List<Runnable> running = new ArrayList<>(25); 
     private List<Runnable> completed = new ArrayList<>(25); 
     private final JProgressBar progressBar; 

     public MainThread(JProgressBar progressBar) { 
      this.progressBar = progressBar; 
     } 

     @Override 
     public void done(Runnable runnable) { 
      synchronized (UPDATE_LOCK) { 
       running.remove(runnable); 
       completed.add(runnable); 
      } 
      int count = running.size() + completed.size(); 
      updateProgress(completed.size(), count); 
      synchronized (WAIT_LOCK) { 
       WAIT_LOCK.notify(); 
      } 
     } 

     protected void updateProgress(final int value, final int count) { 
      SwingUtilities.invokeLater(new Runnable() { 
       @Override 
       public void run() { 
        int progress = Math.round(((float) value/(float) count) * 100f); 
        progressBar.setValue(progress); 
       } 
      }); 
     } 

     @Override 
     public void run() { 
      for (int index = 0; index < 5; index++) { 
       ChildSpawn spawn = new ChildSpawn(this); 
       running.add(spawn); 
      } 
      for (Runnable runnable : running) { 
       new Thread(runnable).start(); 
      } 

      while (running.size() > 0) { 
       synchronized (WAIT_LOCK) { 
        try { 
         WAIT_LOCK.wait(); 
        } catch (InterruptedException ex) { 
        } 
       } 
      } 
      System.out.println("I'm all done"); 
     } 
    } 

    public static class ChildSpawn implements Runnable { 

     private CallBack callBack; 

     public ChildSpawn(CallBack callBack) { 
      this.callBack = callBack; 
     } 

     @Override 
     public void run() { 
      try { 
       Thread.sleep((long)Math.round(Math.random() * 5000)); 
      } catch (InterruptedException ex) { 
      } 

      callBack.done(this);    
     } 

    } 

} 
+0

嗨MadP,你的例子讓我明白了我應該這樣做的方式,過了一段時間,我已經運行了。我仍然需要做一些小調整,但是,嘿,謝謝!另一方面,如果你想打賭,你可能會失敗。我妻子在工作,我是這裏的一個病人,照顧我的三個女孩(9歲,4歲和2歲,沒有手打字)。 無論如何,祝賀你的寶貝,我知道你可能會對此感覺如何。 :) – gobispo

+0

很高興幫助!喜歡線程;) – MadProgrammer