2

I recently saw a MVC java application in which the main method was written as:

    public static void main(String[] args) 
    {
        SwingUtilities.invokeLater(new Runnable() 
        {
            public void run() 
            {
                View view = new View();
                Model model = new Model();
                Controller controller = new Controller(view, model);
                controller.start();
            }
        });
    }

Wouldn't this make all the program (including both the model and the controller, that have nothing to do with Swing at all) run until the code ends in the AWT Event Dispatch Thread instead of the Main thread?

If this last was true, then that would be really bad for the app as it would block the EDT from carrying out the tasks it needs to (dispatching events, for example, as the model could be calculating other tasks). Is it correct?


There is a similar old post (not a duplicate from this one) that can suggest the code mentioned above is good practice, so it confused me even more.

hexstorm
  • 318
  • 4
  • 14
  • 3
    Yes the model and controller effect Swing. You can't paint a Swing component if you don't have access to the data in the model. The controller notifies the view when the model has changed so the component can be repainted. So yes, the majority of the code will always execute on the EDT since all listener code executes on the EDT. The only code that doesn't execute on the EDT is when you create a Thread for long running background tasks. In those threads if you ever need to update the GUI you then need to use `invokeLater(...)` as well, or use a SwingWorker instead of a Thread. – camickr Mar 11 '21 at 15:27
  • 1
    There is no UI before this `run()` method starts (and therefore no events to process, no repainting to be done). It stands to reason that what `controller.start()` does is make the whole UI visible and before that there is just nothing else to be done on the EDT. – Thomas Kläger Mar 11 '21 at 15:42
  • 1
    So wouldn't it be much better to have the model, view and controller running on the main thread and use `invokeLater(...)` only in the view methods that really need to create/update the Swing UI? I don't see why should they all run in the EDT instead of the main thread. – hexstorm Mar 11 '21 at 15:47
  • 2
    The purpose of the code fragment that you show is to **create** the Swing UI and the model and to connect them together. There is no Swing _update_ (in terms of reacting to user input) since there cannot be any user input before the `run()` methods ends. While you could split these tasks between main thread and EDT (and possibly gain a few milliseconds until the UI is first shown) it would also complicate the design of the application (multithreading is no easy topic) and litter the code base with `invokeLater()` calls. I would not do it until someone proves it to be necessary. – Thomas Kläger Mar 11 '21 at 18:55
  • @ThomasKläger I see what you're saying, and yes the easiest and cleanest way by far would be to do it with a single `invokeLater()` on the main. But what if when creating the model it needs to read some files and instead of delaying a few milliseconds it delays a whole second? The point is that every code is different, and I believe only code creating or updating Swing should go to the EDT. With the approach you suggest, the EDT becomes the main thread. – hexstorm Mar 12 '21 at 07:55
  • You are confused between [invokeLater()](https://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#invokeLater(java.lang.Runnable)) and [invokeAndWait()](https://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#invokeAndWait(java.lang.Runnable)) the former is asynchronous and there is no BLOCKING but the later will wait for completion in the awt thread. Choice is yours – Sync it Mar 15 '21 at 05:09

1 Answers1

1

The purpose of the code fragment that you show is to create the Swing UI and the model and to connect them together.

There is no Swing update (in terms of reacting to user input) since there cannot be any user input before the run() methods ends.

While you could split these tasks between main thread and EDT (and possibly gain a few milliseconds until the UI is first shown) it would also complicate the design of the application (multithreading is no easy topic) and litter the code base with invokeLater() calls. I would not do it until someone proves it to be necessary.


IMHO the EDT is the main thread in any GUI application. Every reaction to user input starts in this thread and every update of the UI must be done in this thread.

Long running tasks should be done in a background thread - which usually means anything that takes more than a few milliseconds.

What if creating the model takes several seconds?

In that case I would try to split the model creation into two parts:

  • create the minimal part that is needed so that the UI can be shown. This should be done in the EDT (because the user has to wait for the completion of this part anyway - before the UI is shown he cannot interact with it)
  • do the remaining, long running parts in a background thread.

What if this cannot be done? (i.e. the UI cannot be displayed until the model is fully initialized)

In this case the user has to wait for the complete initialization of the model before he can see and use the UI anyway. So it doesn't matter whether this initialization runs on the EDT or the main thread. So use the simpler solution: everything on the EDT.

But give the user some hint that your application is starting by showing a splash screen

Thomas Kläger
  • 17,754
  • 3
  • 23
  • 34
  • So the takeaway should be that although you could spread the work between the Main and ED Threads, doing it all on the EDT is much better practice as it should be the "main thread" of your Swing app (you'll avoid complexity without having to deal with multithreading and you'll be sure to update your UI from the EDT). Thank you very much!! – hexstorm Mar 16 '21 at 09:43