简体   繁体   中英

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

I have 3 primary classes in my program. 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.

The GUI class communicates with the back-end thread several times to get data to display on the screen. My problem is that the GUI is displaying its components before the back-end class supplies them with data. 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. I've tried several variations of:

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

on the GUI class, and placing 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. I've tried adding the synchronized keyword to the two methods, but this causes the program to freeze.

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.

EDIT: As per @MadProgrammer's suggestion, I'm utililzing a SwingWorker and it seems to be doing the trick. 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. This will make your application "hang" and prevent the UI from been updated (or responding to any input from the user).

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. This should allow you UI to display something like a "wait" message while it waits for data from the data thread.

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.

Make sure that all creation/modification/interaction with the UI is done within the context of the Event Dispatching Thread.

Take a look at Concurrency in Swing for more details

Updated

The basic work flow (IMHO) should look something like...

  • UI - request data from background thread, pass a listener interface to the background thread (with methods like loadingDone and loadingFailed for exmaple
  • UI - Display "loading" message. May display a nice animated GIF
  • Thread - When data is loaded (assuming it all went well), package the data and passing it back via the loadingDone method
  • UI - When loadingDone is called, re-sync with the EDT (using SwingUtilities.invokeLater ) and update the UI.

This would actually be simpler with a SwingWorker and it would provide progress updates built in

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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