2009-11-24 2 views
1

Я отлаживаю код, написанный с помощью SwingWorker, для выполнения комбинации численного расчета и обновления графического интерфейса пользователя. 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 нити, которые выполняются. Могут ли они работать с тем же потоком?

UPDATE: Вот код, который выполняет SwingWorker:

общественности окончательное недействительным одушевленные (финальные длинные delayBetweenUpdatesMilliseconds, окончательный список modelIndices, окончательное логическое keepTrace, окончательный список propertyChangeListeners) {

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

modelAnimator.execute(); 

}

+1

Я не эксперт, но похоже, что вы зашли в тупик. Как выглядит код, который вызывает этот метод? – ChadNC

+0

Привет, Чад, спасибо за ответ. Я думал, что если бы у меня был тупик, трассировка стека показала бы это - обычно это то, что он делает. Код, который вызывает это, просто выполняет() в SwingWorker. –

+0

Возможны последовательные вызовы спать(). Поток все еще может спать, когда вы вызываете второй звонок, и это может быть причиной тупика.Я всегда создавал экземпляр объекта runnable для рабочих потоков. – ChadNC

ответ

1

Это несоблюдение правил качания EDT.

Целью SwingWorker является выполнение тяжелых задач nonGUI при возникновении события пользовательского интерфейса, которое в противном случае блокирует пользовательский интерфейс, а затем обновляет пользовательский интерфейс в конце.

Таким образом, вы бы выполнили свой подъем веса внутри doInBackground(); то после завершения качания вызовет done() на EDT, и вы сможете получить результаты, используя get().

Проблема заключается в том, что вы работаете с графическим интерфейсом в новом потоке SwingWorker. Это может привести к возникновению взаимоблокировок и параллелизма.

Это включает в себя создание указанных объектов GUI, который должен быть в runnables даже если ваш уже на действия EDT

, таких как:

b = getButtonByIndex(index); 

Должен быть заключен в Runnable с InvokeandWait. Вещь, которая на самом деле изменяет сам GUI, особенно должна быть в их собственных runnables, даже, если ваш уже в потоке отправки события свинг-ответа, нажав или нажав кнопку, вы рискуете работать с объектами, над которыми вы уже работаете.

например. swing работает и блокирует A, чтобы вы могли работать, позволяя вам работать на B, пытающемся блокировать и работать на A

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