简体   繁体   English

如何使用wait()和notifyAll()在GUI类和逻辑线程之间进行通信

[英]How to use wait() and notifyAll() to communicate between a GUI class and logic thread

I have 3 primary classes in my program. 我的程序中有3个初级班。 The first extends applet (and acts as my main), the second is a thread (implementing Runnable) that handles the back-end logistics / communication with the server, and the third is a JPanel class, which creates the GUI (this is created in a new thread by way of a call to SwingUtilities.invokeAndWait() in the main (applet) class. 第一个扩展小程序(并充当我的主程序),第二个扩展是处理后端物流/与服务器通信的线程(实现Runnable),第三个扩展是创建GUI的JPanel类(创建通过调用主(小应用程序)类中的SwingUtilities.invokeAndWait()在新线程中进行操作。

The GUI class communicates with the back-end thread several times to get data to display on the screen. GUI类与后端线程多次通信,以获取要在屏幕上显示的数据。 My problem is that the GUI is displaying its components before the back-end class supplies them with data. 我的问题是,在后端类向其提供数据之前,GUI正在显示其组件。 So, I want to tell the GUI to call a method in the other thread, wait to hear back from it, and then display its components. 因此,我想告诉GUI在另一个线程中调用一个方法,等待它的回音,然后显示其组件。 I've tried several variations of: 我尝试了以下几种变体:

Object[] data = backend.Method1(); 
wait();
showComponents(data);

on the GUI class, and placing notifyAll(); 在GUI类上,并放置notifyAll(); at the bottom of Method1 in the back-end thread, but I get a warning in netbeans (Invoking Object.wait outside of a synchronized context), and the program crashes on a java.lang.illegalmonitorstateexception when it runs. 在后端线程Method1的底部,但是我在netbeans中收到警告(在同步上下文之外调用Object.wait),并且该程序在运行时在java.lang.illegalmonitorstateexception上崩溃。 I've tried adding the synchronized keyword to the two methods, but this causes the program to freeze. 我曾尝试向这两种方法中添加synchronized关键字,但这会导致程序冻结。

I'm (obviously, I'm sure) just learning about multi-threading: What am I misunderstanding here? 我(显然,我确定)只是在学习多线程:我在这里误解了什么?

I have a feeling that its relevant that the JPanel class does not implement runnable. 我觉得JPanel类未实现runnable与之相关。

EDIT: As per @MadProgrammer's suggestion, I'm utililzing a SwingWorker and it seems to be doing the trick. 编辑:根据@MadProgrammer的建议,我正在使用SwingWorker,它似乎可以解决问题。 Thanks for pointing me to it, I had never heard of them before. 感谢您为我指出这一点,我以前从未听说过它们。

 final JLabel loading = new JLabel("loading");
    loading.setVisible(true);
    add(loading);

    SwingWorker sw = new SwingWorker<Map<String, ArrayList<Time[]>>, Void>() {
        @Override
        public Map<String, ArrayList<Time[]>> doInBackground(){
            System.out.println("doing");
            Map<String, ArrayList<Time[]>> toReturn = dbh.getTimes(specToPass);
            return toReturn;
        }

        public void done(){
            try {
                loading.setVisible(false);
                Map<String, ArrayList<Time[]>> weekMap = new HashMap(this.get());
                showTimes(weekMap);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            } catch (ExecutionException ex) {
                  ex.printStackTrace();
            }
       }
    };
    sw.execute();

I hope you'll let me know if I'm not implementing this properly. 希望您能告诉我是否执行不正确。 Thanks again. 再次感谢。

DON'T. 别。 Blocking the UI in any way is ALWAYS a bad idea. 以任何方式阻止UI总是一个坏主意。 This will make your application "hang" and prevent the UI from been updated (or responding to any input from the user). 这将使您的应用程序“挂起”,并防止UI更新(或响应用户的任何输入)。

This makes a very bad user experience. 这使用户体验非常差。

Instead, use some kind of call back that allows the data thread to send updates back to the UI as is required. 相反,请使用某种回调,该回调允许数据线程根据需要将更新发送回UI。 This should allow you UI to display something like a "wait" message while it waits for data from the data thread. 这应该使您的UI在等待数据线程中的数据时显示“等待”消息。

You could also use a SwingWorker to handle the data collection, but it might be to simple for your over all needs, but it provides simple methods for synchronizing any updates back to the UI. 您也可以使用SwingWorker来处理数据收集,但是对于您的所有需求来说可能很简单,但是它提供了将所有更新同步回UI的简单方法。

Make sure that all creation/modification/interaction with the UI is done within the context of the Event Dispatching Thread. 确保在事件分发线程的上下文中完成所有与UI的创建/修改/交互。

Take a look at Concurrency in Swing for more details 查看Swing中的并发以了解更多详细信息

Updated 更新

The basic work flow (IMHO) should look something like... 基本工作流程(IMHO)应该类似于...

  • UI - request data from background thread, pass a listener interface to the background thread (with methods like loadingDone and loadingFailed for exmaple loadingDone从后台线程请求数据,将侦听器接口传递到后台线程(使用loadingDoneloadingFailed这样的方法进行loadingDone
  • UI - Display "loading" message. UI-显示“正在加载”消息。 May display a nice animated GIF 可能会显示精美的GIF动画
  • Thread - When data is loaded (assuming it all went well), package the data and passing it back via the loadingDone method 线程-加载数据时(假设一切顺利),打包数据并通过loadingDone方法传回
  • UI - When loadingDone is called, re-sync with the EDT (using SwingUtilities.invokeLater ) and update the UI. loadingDone调用loadingDone ,与EDT重新同步(使用SwingUtilities.invokeLater )并更新UI。

This would actually be simpler with a SwingWorker and it would provide progress updates built in 使用SwingWorker实际上会更简单,并且它将提供内置的进度更新

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM