代码之家  ›  专栏  ›  技术社区  ›  Amir Afghani

爪哇摇摆工人绞刑

  •  2
  • Amir Afghani  · 技术社区  · 15 年前

    我正在调试一些代码,这些代码是使用swingworker编写的,用于执行数值计算和GUI更新的混合。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
    

    $Works.Run(TyRePoLeExcel).java:908 在Java.Lang.Trime.Run(线程.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的代码:

    public final void animate(final long delaybetween nupdates毫秒, 最终列表模型索引, 最终布尔保持空间, 最终列表PropertyChangeListeners){

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

    }

    1 回复  |  直到 15 年前
        1
  •  1
  •   Tom J Nowell    15 年前

    这是未能遵守Swing EDT规则。

    SwingWorker的目的是在发生会阻塞UI的UI事件时执行大量非UI任务,然后在结束时更新UI。

    因此,您可以在doinbackground()内实现举重;完成后,Swing将在EDT上调用Done(),并且可以使用get()检索结果。

    这里的问题是,您正在使用新的线程swingworker创建的GUI工作。这可能导致死锁和并发问题。

    这包括创建所说的GUI对象,这些对象应该是可运行的,即使您已经在EDT上了。

    行动,如:

    b = getButtonByIndex(index);
    

    应该用invokeAndWait封装在可运行文件中。实际上修改图形用户界面本身的东西,尤其需要在自己的可运行文件中, 即使 如果您已经在Swing事件分派线程中响应按钮按下或更改,那么您将面临处理已经处理的对象的风险。

    例如,Swing正在工作并锁定a以允许您工作,让您在b上工作尝试锁定并在a上工作