2009-11-24 44 views
1

我正在調試一些使用SwingWorker編寫的代碼來執行數值計算和GUI更新的混合。該SwingWorker類掛起與以下堆棧跟蹤:Java SwingWorker掛

Full thread dump Java HotSpot(TM) Client VM (14.3-b01 mixed mode, sharing): 

"SwingWorker-pool-3-thread-4" prio=6 tid=0x07fd7c00 nid=0x143c waiting on condition [0x0a33f000] 
    java.lang.Thread.State: TIMED_WAITING (sleeping) 
     at java.lang.Thread.sleep(Native Method) 
     at sum.ee.ui.modelviewer.ModelViewer$ModelAnimator.doInBackground(ModelViewer.java:940) 
     at sum.ee.ui.modelviewer.ModelViewer$ModelAnimator.doInBackground(ModelViewer.java:877) 
     at javax.swing.SwingWorker$1.call(SwingWorker.java:274) 
     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) 
     at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
     at javax.swing.SwingWorker.run(SwingWorker.java:313) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 
     at java.lang.Thread.run(Thread.java:619) 

"SwingWorker-pool-3-thread-3" prio=6 tid=0x07fd7000 nid=0x11a8 waiting for monitor entry [0x0a2af000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
     at java.awt.Component.resize(Component.java:2044) 
     - waiting to lock <0x24b936a0> (a java.awt.Component$AWTTreeLock) 
     at java.awt.Component.setSize(Component.java:2035) 
     at java.awt.Component.resize(Component.java:2069) 
     at java.awt.Component.setSize(Component.java:2060) 
     at javax.swing.JViewport.setViewSize(JViewport.java:1038) 
     at javax.swing.ViewportLayout.layoutContainer(ViewportLayout.java:183) 
     at java.awt.Container.layout(Container.java:1421) 
     at java.awt.Container.doLayout(Container.java:1410) 
     at jsyntaxpane.components.LineNumbersRuler.updateSize(LineNumbersRuler.java:109) 
     at jsyntaxpane.components.LineNumbersRuler.removeUpdate(LineNumbersRuler.java:203) 
     at javax.swing.text.AbstractDocument.fireRemoveUpdate(AbstractDocument.java:243) 
     at jsyntaxpane.SyntaxDocument.fireRemoveUpdate(SyntaxDocument.java:118) 
     at javax.swing.text.AbstractDocument.handleRemove(AbstractDocument.java:608) 
     at javax.swing.text.AbstractDocument.remove(AbstractDocument.java:576) 
     at javax.swing.JEditorPane.setText(JEditorPane.java:1493) 
     at sum.ee.ui.SourceCodePanel.clearSourcePane(SourceCodePanel.java:256) 
     at sum.ee.ui.SourceCodePanel.access$100(SourceCodePanel.java:47) 
     at sum.ee.ui.SourceCodePanel$1.stateChanged(SourceCodePanel.java:209) 
     at sum.ee.ui.VisualizationAggregator.fireStateChanged(VisualizationAggregator.java:300) 
     at sum.ee.ui.VisualizationAggregator.update(VisualizationAggregator.java:97) 
     at sum.ee.ui.modelviewer.ModelViewer$ModelAnimator.doInBackground(ModelViewer.java:918) 
     at sum.ee.ui.modelviewer.ModelViewer$ModelAnimator.doInBackground(ModelViewer.java:877) 
     at javax.swing.SwingWorker$1.call(SwingWorker.java:274) 
     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) 
     at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
     at javax.swing.SwingWorker.run(SwingWorker.java:313) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
     at java.util.concurrent.ThreadPoolExecutor 

$ Worker.run(ThreadPoolExecutor.java:908) 在java.lang.Thread.run(Thread.java:619)

我的理解是GUI工作不應該在doInBackground()內完成,而應該在done()中完成。我將doInBackground()中的所有代碼移動到done()中,然後執行了一個天真的實驗,但它仍然無法工作。是否有任何提示,人們可以給我什麼我能做的根源導致這個問題?代碼如下所示:

protected Void doInBackground() { 
    isAnimating = true; 
    resetButtonBackgrounds(); 
    backgroundColor = new Color(175, 255, 175); // Soft Green 

    JToggleButton b = null; 
    for (final int index : modelIndices) { 
     if (index == modelIndices.get(modelIndices.size() - 1)) { 
      backgroundColor = defaultBackgroundColor; 
     } 
     if (!keepTrace) { 
      // Resetting the backgrounds is necessary to have 
      // individual display of the changing elements due to 
      // the fact that there can be multiple nodes per 
      // source line. The reset works in combination 
      // with updating from ModelViewer.this (as opposed 
      // to the 'this' of ModelAnimator instances) due 
      // to not sending an event to itself. Furthermore, 
      // if the event was sent from ModelAnimator, the model 
      // indices are recalculated, causing a jump when multiple 
      // element source lines are encountered. 
      resetButtonBackgrounds(); 
     } 
     aggregator.modelIndex(index); 
     aggregator.update(ModelViewer.this); 

     b = getButtonByIndex(index); 
     scrollRectToVisible(b.getBounds()); 
     ModelViewer.this.repaint(); 
     try { 
      StaticTools.sleepAtLeast(sleepTimeMilliseconds); 
     } catch (final InterruptedException ex) { 
      // continue with thread 
     } 
    } 

    isAnimating = false; 

    if (b != null) { 

     Color orig = b.getBackground(); 
     Color blink = Color.PINK; 
     Color current = orig; 
     for (int i = 0; i < 100; i++) { 

      try { 
       Thread.sleep(100); 
      } catch (InterruptedException ex) { 
      } 

      if (current == orig) { 
       current = blink; 
      } else { 
       current = orig; 
      } 

      b.setBackground(current); 
      ModelViewer.this.repaint(); 

     } 
    } 

    return null; 
} 

另一個線索是,有一些執行兩個線程的SwingWorker。他們可以運行相同的線程嗎?

更新:這是執行的SwingWorker代碼:

公衆最終無效動畫(最終長delayBetweenUpdatesMilliseconds, 最終名單modelIndices, 最終布爾keepTrace, 最終名單的PropertyChangeListeners){

ModelAnimator modelAnimator = 
     new ModelAnimator(delayBetweenUpdatesMilliseconds, modelIndices, 
     keepTrace); 
for (final PropertyChangeListener listener : propertyChangeListeners) { 
    modelAnimator.addPropertyChangeListener(listener); 
} 

modelAnimator.execute(); 

}

+1

我不是專家,但它看起來像你有一個僵局。代碼看起來是什麼調用該方法? – ChadNC 2009-11-24 20:32:37

+0

嗨乍得,謝謝你的迴應。我想如果我有一個死鎖,堆棧跟蹤會顯示它 - 那通常是它所做的。調用它的代碼只是在SwingWorker上執行execute()。 – 2009-11-24 20:39:26

+0

可能是連續的睡眠呼叫()。當第二次呼叫進入睡眠狀態時,該線程可能仍然處於睡眠狀態,這可能是造成死鎖的原因。我一直爲工作線程創建了一個可運行對象的實例。 – ChadNC 2009-11-24 20:47:43

回答

1

這是無法觀察Swing EDT規則的。

SwingWorker的目的是在UI事件發生時執行繁重的非GUI任務,否則UI事件會阻塞UI,然後在最後更新UI。

所以你會在doInBackground()中實現你的舉重。那麼一旦完成擺動將在EDT上調用done(),並且可以使用get()檢索結果。

這裏的問題是你正在SwingWorker創建的新線程中進行GUI工作。這可能導致死鎖和併發問題。

這包括創建表示GUI對象,這應該是在可運行,即使你已經在美國東部時間

操作如:

b = getButtonByIndex(index); 

應與InvokeandWait一個Runnable包住。實際上修改GUI本身的東西尤其需要在他們自己的可運行模式中,如果您已經在回調按鈕按下或更改的回調事件調度線程中,那麼您將面臨處理已處理對象的風險。

例如擺動正在工作和鎖定A讓你做工作,讓你做B的工作試圖鎖定和工作A