• Post Reply Bookmark Topic Watch Topic
  • New Topic

Understanding the fundamentals of threading in Swing applications  RSS feed

 
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hey ho everyone,

I would really appreciate your feedback if my current understanding of threading in Swing is correct or hints where I go wrong. I wrote a really basic MVC app that is using a JFrame to display the GUI:



The controller gets called to handle all interactions with the gui and initially creates the window (JFrame is passed by the GUI class). So far there should be the main application thread and the Swing / EDT that is used to display the GUI:



Going from here  action handlers in the view call methods in the controller. These handlers run on the EDT. So when the handler calls a controller method:



The actions in the controller method are still carried out on the EDT and should be either quick or wrapped in a Swing Worker to keep the GUI responsive. So far I struggle to
have an idea what would be fast enough. Or is it good practice to use Swing Workers for all of these calls coming from EDT event handlers?

Finally, the other way around I understood that all manipulations that call Swing methods should be carried with invokeLater/wait if quick or SwingWorkers if not. In my app all Swing objects are contained in the view
class (except for the initial window creation). The controller calls view methods which manipulate JLabels, Sliders etc.. Is it necessary to wrap all these Swing component handling in the view with InvokeLater and SwingWorker constructs? And
again how to determine what is too lengthy for invokeLater?

Cheers
Mark 

 
Marshal
Posts: 57236
175
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Have you been through the Java Tutorials, and the Swing documentation? Let's see if I can't find them. Found one of them and got them both. If you go through the Java Tutorials' index, you will find a separate section about concurrency somewhere.
You know that Java8+ allows you to abbreviate that anonymous inner class to a λ? You can replace lines 7‑13 with
SwingUtilities.invokeLater(() -> controller.showDesktopAppView());
Similarly for an Action Listener anonymous class:-
blueButton.addActionListener(e -> greenButton.setBackground(Color.RED));
There is something a bit unusual about that, creating the controller outwith the EDT.
Then you get to a long task, which you are going to perform with a SwingWorker object, presumably. The tutorials link should tell you how to use a swing worker object to create a separate Thread. I don't know how slow you would regard as too slow. Are you doing other things, e.g. animation, on the EDT? If so, you will notice every delay. If your animation is running at intervals of 33ms (about 30 times per second), you will probably notice jerkiness to your animation if the swing worker takes > 25ms to complete a task on the EDT. If you are not noticing any jerkiness or slow responses when you run your app on a slow computer, then assume everything is working fast enough. It isn't really possible to be any more specific than that. If you are downloading something from a website, you need to allow a few seconds even for the quickest query, so you will want a swing worker and a separate thread for that sort of thing. A 2″ delay between your clicking the button and the other button turning red will produce complaints about slow execution from all your users.

The controller calls view methods which manipulate JLabels, Sliders etc.. Is it necessary to wrap all these Swing component handling in the view with InvokeLater and SwingWorker constructs?

On the EDT started with invokeLater? Yes. Using SwingWorker or repeated invokeLater calls? No. I can see no point in using a SwingWorker for something like
resultsTextField.setText("CodeRanch is brilliant");
which anyway will run much faster than the repainting of that component to show the change. A repeated invokeLater call will simply plug you into the EDT which should already be running, so you usually don't need that either. You can use invokeAndWait(), but once you have tried it and seen how many checked exceptions you have to handle, you will always use invokeLater in future

I hope this has answered your question; sorry if I have answered something completely different.
 
mark q. murphy
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you Campbell Ritchie. I'm afraid despite your much appreciated effort your reply didn't solve my problem completely. So bear with me. But I think you put me on the right track. We'll see...

So starting again at the beginning:



So here we have the "main thread" and the "Swing Thread" aka EDT. Since view and controller are wrapped in an invoke later construct they are created in the EDT and
anything that happens inside and between those to stays on the EDT. Unless it calls on components that run in a different thread or includes creation of a new thread like swing worker (even though that
returns to the EDT). Listener action happens on the EDT.

So anything in there that is to lengthy for the GUI needs a SwingWorker. Otherwise no invokeLarters are necessary since it is happening in the EDT anyway. When the view calls on the playlist/model that is
started from the EDT since that's were the controller acts. Model actions initiated by the controller then happen on the main thread and may move on to other threads, but returns to the EDT when the call returns to
the controller. So this won't require any inivokeLater actions to bring back to the EDT. Slow going model stuff also doesn't affect the EDT since it happens elsewhere. Only if the action in the controller prior or past the model action
would be lenghty that calls for a SwingWorker. But seems wrong anyway since the controller should not work hard and only coordinate things, right?

I hope that's right so far and I did not mess up completely now. The only thing I am unclear about now is listening. The controller is a listener of the model. Which reside in different threads. Therefore, I assume that either
the model notifyListeners() call should be wrapped with an invoke later (if all listeners are EDT residents) or maybe better the listener should start its reactToNotification() method to sync ingoing listener events with the EDT?

 
Sheriff
Posts: 23090
45
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm not sure about all that, but I can say that Swing listeners are always called on the EDT. Adding a listener to a component is a trivial task, and it's usually part of the UI anyway so just do it. But as for what to do inside a listener when it receives an event from its component: that's where you have to decide whether to do the work in a separate thread or not.

Hope that clarifies things a little bit?
 
mark q. murphy
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sorry I made that terribly unclear. While most of my listener remarks regard "default" action and mouse listeners, the last section of my post refers to listeners I coded my self, which
inform the controller about changes in the model e.g. the playlist to update the view accordingly.

Was the

I'm not sure about all that

remark the polite way for telling me it is utterly wrong or is that just me being paranoid, because I spend to much time with the English?
 
Rancher
Posts: 3220
37
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Where (which thread) an object is created has no effect on which thread it can run on.

Which thread it runs on depends on which thread it was called from.

So, in your example, even though playlist is instantiated in the Main thread, if it is accessed (via a call to the controller in a listener for example) in the EDT it will run in the EDT.

eg


That code runs on the EDT.
If skipBwd happened (for whatever reason) to call something on playlist then that would also run on the EDT.
The only way for it to not run on the EDT is for it to be launched in another thread, eg via a SwingWorker.
 
Paul Clapham
Sheriff
Posts: 23090
45
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

mark q. murphy wrote:Was the

I'm not sure about all that

remark the polite way for telling me it is utterly wrong or is that just me being paranoid, because I spend to much time with the English?



No, it just made my head hurt trying to read it all.
 
mark q. murphy
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks Dave. Your reply put me on the right track and made me see where I was thinking in the wrong direction. Since my own listeners are still event listeners their actions will be executed on the EDT.

Since all calls in the application are either initiated by user GUI interactions or model changes, which all result in listener actions the only thing to take care of is to use Swing Workers in case of long running processes.
Plus using Invoke later to set up the GUI initially. I will still have a good look at the Oracle general threading tutorial. Shouldn't do me any harm.

 
Paul Clapham
Sheriff
Posts: 23090
45
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

mark q. murphy wrote:Since all calls in the application are either initiated by user GUI interactions or model changes, which all result in listener actions the only thing to take care of is to use Swing Workers in case of long running processes. 



Yeah! That's a much clearer description of why and how to use threads in a Swing application.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!