【问题标题】:Swing Worker threads stop executing code unexpectedlySwing Worker 线程意外停止执行代码
【发布时间】:2016-10-29 20:45:24
【问题描述】:

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

程序按预期运行,直到我尝试实现消息显示。为了为每条消息显示一个箭头,我扩展了 SwingWorker UIArrowThread,以添加一个 JLabel,该 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() 中而不是 doInBackground() 中进行工作,以及让 ArrowLabel 从 GUI 中删除自身而不是 UIArrowThread 进行删除。

更新:

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

【问题讨论】:

    标签: java multithreading swing mutex


    【解决方案1】:

    您的片段表明您正在通过SwingWorkerdoInBackground() 方法更新Swing 组件ArrowLabel。这违反了 Swing single-thread rule。相反,请在后台查询服务器、publish() 中间结果,并在 EDT 上查询process() 它们,如检查的示例here 所示。 “用于通过此 SwingWorker 的发布和处理方法执行中间结果的type”的确切公式将取决于您的用例。作为一个具体的例子,这个TableSwingWorker扩展了SwingWorker&lt;MyTableModel, RowData&gt;,发布了RowData的实例用于更新一个TableModel

    【讨论】:

    • 虽然这是我应该练习的,但它并不能解决问题。我已经从 doInBackground() 中删除了所有内容,以便它只有 return 语句并且问题仍然存在。
    • 您可能有其他错误或未报告的异常;另请参阅 Update 6 中引用的 EDT 检查方法 here 和引用 here 的错误报告。
    猜你喜欢
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多