Swing Worker线程意外停止执行代码

时间:2016-10-29 20:45:24

标签: java multithreading swing mutex

我正在尝试使用Swing创建一个测试互斥算法的平台。我的目的是在GUI中显示它们之间发送的服务器和消息。我还想显示一个关键部分,显示当前正在访问它的服务器。我正在使用一个执行SwingWorker线程的线程池来部署加载用户选择的互斥算法的服务器。

程序按预期运行,直到我尝试实现消息显示。为了显示每条消息的箭头,我已经扩展了SwingWorker,UIArrowThread,以添加一个从源服务器向目标绘制箭头的JLabel。在删除JLabel之前,此线程等待1秒。当我明确地创建一个或多个这些消息时,这似乎工作正常(我还创建了一个测试平台,我可以在其中创建特定的消息)。

当我尝试将此SwingWorker线程集成到程序中时出现问题。启动算法时,每个服务器都会尝试访问关键部分并将其请求发送到每个其他服务器。这应该调用UIArrowThread,但似乎只有一些服务器实际上创建了该线程。

public void sendMsg(int destId, Object ... objects) {
    comm.sendMsg(destId, objects);
    try{
        UIArrowThread a = new UIArrowThread(AlgorithmSimulatorUI.jlp,
                                            objects[0].toString(),
                                            comm.getMyId(),
                                            destId);
        AlgorithmSimulatorUI.threadPool.execute(a);
    } catch (Exception exc){
        System.err.println(exc);
    }
}

有些服务器似乎在实例化UIArrowThread之前就停止执行,最终导致死锁。任何使它通过该点的服务器都能正常工作,GUI显示应该是正常的。我在调用UIArrowThread之前和它的构造函数中测试了日志。看起来停止执行的线程永远不会在构造函数中进行日志调用。我很难理解为什么会发生这种情况。

public class UIArrowThread extends SwingWorker<Integer, String>{

JLayeredPane jlp;
String type;
int source;
int target;
Point start;
Point end;
Point[] points;
int quadrant;

public UIArrowThread(JLayeredPane jlp, String msg_type, int source,
                     int target){
    this.jlp = jlp;
    this.type = msg_type;
    this.source = source;
    this.target = target;
    this.points = getPoints();
    this.start = points[0];
    this.end = points[1];
}

@Override
protected Integer doInBackground(){
    Point lblPoint = getLabelCoordinates(points);
    ArrowLabel arrow = new ArrowLabel(type, 1, 2, jlp, points, quadrant);
    if (quadrant < 5){
        arrow.setBounds(lblPoint.x, lblPoint.y, abs(start.x - end.x),
                        abs(start.y - end.y));
    } else if (quadrant < 7){
        arrow.setBounds(lblPoint.x, lblPoint.y, 100, abs(start.y - end.y));
    } else {
        arrow.setBounds(lblPoint.x, lblPoint.y, abs(start.x - end.x), 100);
    }
    jlp.add(arrow);
    String openHTML = "<html><font color='red',size=12>";
    String closeHTML = "</font></html>";
    arrow.setText(openHTML + type + closeHTML);
    arrow.setHorizontalTextPosition(JLabel.CENTER);
    arrow.setVerticalTextPosition(JLabel.CENTER);
    jlp.repaint();
    try{
        Thread.sleep(arrow.lifespan);
    } catch (Exception exc){
        System.err.println(exc);
    } finally {
        jlp.remove(arrow);
    }
    jlp.repaint();
    return 1;
}

我已经添加了我觉得这个问题的相关代码部分。如上所述,如果我删除UIArrowThread,程序将正确运行。

我尝试了一些仍然产生相同结果的方法,包括在process()中执行work而不是doInBackground(),并让ArrowLabel从GUI中移除自己而不是UIArrowThread进行删除。

更新

我能够按预期使UI工作,但仍然不能确定原始问题是什么。该程序有一个消息队列,显示来自textPane中服务器的消息,所以我想我在这里用箭头标签更新UI。不需要更改ArrowLabel或UIArrowThread的任何现有代码。

1 个答案:

答案 0 :(得分:5)

您的片段建议您使用SwingWorkerArrowLabel方法更新Swing组件doInBackground()。这违反了Swing single-thread rule。相反,在后台查询服务器,publish()中间结果,并在EDT上查询process(),如所查看的示例here所示。用于通过此SwingWorker的发布和处理方法执行中间结果的type的确切公式将取决于您的用例。作为一个具体示例,此TableSwingWorker扩展SwingWorker<MyTableModel, RowData>,发布用于更新RowData的{​​{1}}个实例