java - 小程序 - init()、EDT 和线程

标签 java applet event-dispatch-thread

Java 不是我的母语,我已经和这个问题斗争了一段时间了。

基本上,我发现直接从 init() 调用方法 switchApplets() 与从 init() 生成的新线程中调用它之间存在行为差异。

从新线程内部调用它的结果是新的小程序会白屏——直到/除非用户调整浏览器大小或最小化浏览器。如果在 init() 末尾调用,新的 UI 将立即呈现,无需用户输入任何内容。但这不是一个选项,因为它不会等待线程完成其准备工作。

精简代码:

public class PreLoader extends Applet implements AppletStub {

static JProgressBar pBar = null;
static JLabel message;

public void switchApplets() {
    try {
        Class main_class = Class.forName("MainClass");
        Applet main_applet = (Applet)main_class.newInstance();
        removeAll();
        setSize(0,0);
        setLayout(new GridLayout(1,0));
        add(main_applet);
        main_applet.init();
        main_applet.start();
        main_applet.setStub(this);
    }
    catch (Exception e) {
    }
}

public void init() {

    pBar = new JProgressBar(0, 100);
    pBar.setValue(0);
    pBar.setStringPainted(true);

    message = new JLabel("Beginning work!");

    add(message);
    add(pBar);

    FlowLayout flow = new FlowLayout();

    setLayout(flow);

    Thread t = new Thread ( new Runnable () {
        public void run ()
        {
            longRunningFunction1();
            longRunningFunction2();
            message.setText("Work complete! Stand by..");
            switchApplets(); //does NOT work as intended from here
            return;
        }
    } );
    t.start();
    //switchApplets(); //works as intended if called HERE
}

public void longRunningFunction1() {
    //perform some tasks, advance progress bar
}

public void longRunningFunction2() {
    //perform some tasks, advance progress bar
}

public void start() {
    return;
}

public void appletResize(int width, int height) {
    return;
}

}

我尝试让 init() 等待线程完成,以便我可以从那里调用 switchApplets(),但这只会阻止 EDT 并阻止 UI 更新。还尝试使用 SwingUtilities 的 invokeLater/invokeAndWait,但即使 switchApplets() 在 EDT 上运行,似乎也必须直接从 init() (或至少是运行 init 的线程)调用它才能达到所需的效果.

为什么从新线程中调用 switchApplets() 会导致 UI 行为略有不同(且不需要)?

最佳答案

The consequence of calling it from inside the new thread is that the new applet whitescreens -- until/unless the user resizes or minimizes their browser.

这可能是由于尝试在错误的线程上执行 UI 代码而导致的死锁。

I tried making init() wait for the thread to finish so that I could call switchApplets() from there, but that only blocked the EDT and prevented the UI from updating.

你走在正确的道路上。您只需要从 EDT 中调用 switchApplets(),并且仅在其他线程上完成工作后调用。

您确定在长时间运行的函数完成后尝试在生成的线程中使用invokeLater() 或invokeAndWait() 吗?自从我做小程序以来已经很长一段时间了,但我不知道它不起作用的任何特定于小程序的原因,并且它在任何其他情况下都可以工作。即,

public void run()
{
    longRunningFunction1();
    longRunningFunction2();
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            message.setText("Work complete! Stand by..");
            switchApplets();
        }
    });
}

但是,最正确的方法是使用 SwingWorker而不是手动创建的线程。 SwingWorker(它并不像应有的那样广为人知)的设计正是为了在单独的线程上执行后台任务,同时仍然能够通过进度更新和结果来更新 GUI。例如,

new SwingWorker<Void,Void>() {
    @Override
    protected Void doInBackground() { // is called on a background thread
        longRunningFunction1();
        longRunningFunction2();
        return null;
    }

    @Override
    protected void done() { // is called on the Swing thread
        message.setText("Work complete! Stand by..");
        switchApplets();
    }
}.execute();

Void 内容是因为 SwingWorker 还能够返回结果并发送中间进度更新,但此示例不使用这些功能。

您表示您的长时间运行的函数也在更新进度条。这是另一件只应该发生在 Swing 线程上的事情。在实践中,你通常可以不使用它,但它很危险。您的进度更新可以使用 SwingUtilities.invoke 方法之一,或 SwingWorker 的机制;两者都应该有效。 (SwingWorker 本身提供了两种不同的方式来做到这一点:调用 addPropertyChangeListener (Swing 线程)和 setProgress (后台线程),或者调用 publish (后台线程)并覆盖 process (Swing 线程)。)

另外,一个小建议:如果处理检查异常不方便(或者不可能有效地这样做),您至少应该捕获并重新抛出它作为未经检查的异常,而不是捕获并忽略它:

catch (Exception e) {
    throw new RuntimeException(e);
}

这样,任何异常的堆栈跟踪和错误消息都不会丢失。

关于java - 小程序 - init()、EDT 和线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19623361/

相关文章:

java - 如何使用 javax.swing.Timer 暂停 GUI 程序

java - EDT 具体方法和其他内容

javascript 弹出窗口未获取托管值

java - publishOn 和并行的区别

java - 使用 shell 脚本的 xml 模式验证

Java Applet运行时闪烁? (不是每个人都看到闪烁)

java - 了解频繁更新的真实模型中的 EDT

java - 为什么Object已经初始化了,其值还是null?

java - 如何从 Applet 中模拟模态对话框?

java - 小程序在jsp中动态加载