Win a copy of Design for the Mind this week in the Design forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Spawing operations off to separate threads Vs executing on the EDT

 
Sean Keane
Ranch Hand
Posts: 582
Chrome Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi folks. I have a pretty general question I was wondering if someone could answer. Should you always spawn potentially long running operations off on separate threads rather than executing them on the EDT? Or are there cases where it is OK to run potentially long running operations on the EDT?

My question has arisen mainly because I initially spawned such operations off to separate threads. Simply because I read that it was best practice to do so.

However, now that I have implemented my code in this manner, I am failing to see the benefit of it in my particular scenario.

My particular scenario is that I have an application where you can search for records and results are displayed. The flow is as follows:

1) User enters search criteria into a text field.
2) User clicks on a button.
3) I set the state of the cursor on the entire window to the state of WAIT_CURSOR.
4) I execute an operation that communicates with a server to carry out the search.
5) Search results are updated in a table.

6) I set the state of the cursor on the entire window to the state of DEFAULT_CURSOR.


Now I was carrying (4) and (5) out in a separate thread. But what am I actually gaining from this over just executing these two operations on the EDT?

The only reason I have read for spawning potentially long running operations off to separate threads, rather than executing on the EDT, is that if you execute them on the EDT it may cause your GUI to freeze up.

But in my particular example here, I don't want the user to be able to interact with the GUI whilst the operations (4) and (5) are being carried out. I set the WAIT_CURSOR on the entire window to prevent the user interacting with the application.

So would it be acceptable for me to execute all of my operations on the EDT? Or are there problems that I am missing here?
 
Sean Keane
Ranch Hand
Posts: 582
Chrome Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One thing I was thinking about was that a user can still resize my window even though I have set the cursor on the window to the state of WAIT_CURSOR.

So out of curiosity I decided to put my long running operation into a SwingWorker. I put operation on the server side to sleep for a few seconds just to simulate a very long operation. I then executed the operation through the GUI and attempt to resize the window. I was expecting the window to repaint\resize etc when I made it smaller, but it did not. The window didn't repaint and reorganise itself to fit the reduced screen size until the done() method of the SwingWorker had executed.
 
Ranganathan Kaliyur Mannar
Bartender
Posts: 1101
10
Java Netbeans IDE Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
As you have mentioned, having a long-running operation does make the GUI unresponsive. And this is the main reason it is considered a best practice to move it separetely into a worker.
Even moving your mouse generates events on the EDT (say MouseListener), leave alone resizing - in this case events will queue up without getting executed making the GUI unresponsive.
As for your problem, you can make the buttons/menus disabled when the operation is happening and re-enable them in the done method.
However, I am curious about the test you tried and the results you got...so, I am going to try it out myself.
 
Martin Vajsar
Sheriff
Posts: 3752
62
Chrome Netbeans IDE Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean Keane wrote:So out of curiosity I decided to put my long running operation into a SwingWorker. I put operation on the server side to sleep for a few seconds just to simulate a very long operation. I then executed the operation through the GUI and attempt to resize the window. I was expecting the window to repaint\resize etc when I made it smaller, but it did not. The window didn't repaint and reorganise itself to fit the reduced screen size until the done() method of the SwingWorker had executed.

In my app, the windows can be freely resized while SwingWorker executes. Didn't you call the lengthy operation from the done() method itself? SwingWorker.done() is in fact called on EDT.
 
Ranganathan Kaliyur Mannar
Bartender
Posts: 1101
10
Java Netbeans IDE Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Martin Vajsar wrote:In my app, the windows can be freely resized while SwingWorker executes.

Same in my case too. I tried a small example by calling Thread.sleep(10000) for 10 seconds and I am able to resize the frame freely. Post your SSCCE
 
Sean Keane
Ranch Hand
Posts: 582
Chrome Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the replies guys. I haven't got my code infront of me here but I will check tonight. However I am pretty sure I did something incorrect in my code.

Originally I was spawning off the long running task in a normal thread. I thought when I ran this example that the contents of the window was not getting repainted\resized when I resized the window during the long running operation.

Last night I created an example that used the SwingWorker class instead. In this example, my window contents did get repainted\resized when I resized the window. So happy days

I've a feeling that maybe I was starting the thread incorrectly in my first example i.e. maybe using run() instead of start().

Below is a simple example that shows even a Thread on it's own (rather than the SwingWorker) should allow me to resize the window and for the window to be repainted\refreshed:

 
Martin Vajsar
Sheriff
Posts: 3752
62
Chrome Netbeans IDE Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean Keane wrote:Below is a simple example that shows even a Thread on it's own (rather than the SwingWorker) should allow me to resize the window and for the window to be repainted\refreshed...

Yes, it's true. SwingWorker is an extension of such a simple background thread that provides means to communicate the progress or results of the processing to the EDT/user interface.
 
Ranganathan Kaliyur Mannar
Bartender
Posts: 1101
10
Java Netbeans IDE Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Martin Vajsar wrote:Yes, it's true. SwingWorker is an extension of such a simple background thread that provides means to communicate the progress or results of the processing to the EDT/user interface.


Very true. SwingWorker is a much needed class which should have been in the JDK long time back. With generics, it has become really cool to use.
 
Rob Spoor
Sheriff
Pie
Posts: 20511
54
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
SwingWorker was available before Java 6, only it was unofficial and wasn't in the API. See http://en.wikipedia.org/wiki/SwingWorker for more information.

But yes, it's great to have it in the official API
 
Darryl Burke
Bartender
Posts: 5125
11
Java Netbeans IDE Opera
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
... so long as this bug doesn't resurface. It's not yet officially marked as resolved ( ) but in included in the fix list for 6u21.
 
Stephan van Hulst
Bartender
Pie
Posts: 5574
53
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean, also consider that you may want to be able to cancel a task, or update some sort of progress bar. You should always keep the UI responsive, even if there's nothing you can do with it at a given time.
 
Ranganathan Kaliyur Mannar
Bartender
Posts: 1101
10
Java Netbeans IDE Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Darryl Burke wrote:... so long as this bug doesn't resurface. It's not yet officially marked as resolved ( ) but in included in the fix list for 6u21.

oops...this is scary
 
Ranganathan Kaliyur Mannar
Bartender
Posts: 1101
10
Java Netbeans IDE Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This thread leads me to another question:

Suppose I write a chat client - I would start a Thread to talk to the SocketServer and use the blocking 'read()' method in the thread. When I recieve message from the server, I would append it to the textArea. This call would be made in invokeLater.

Now, is SwingWorker a good candidate to replace the thread? i.e technically yes, but it doesn't sound the right fit to me. This is because, I would append to the textAre via the 'process' method - but in this case, the done will be called only when socket closes. SwingWorker is good for long-running task...but what about continous-running job? - or is this just gobbledegook?
 
Rob Spoor
Sheriff
Pie
Posts: 20511
54
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That's what publish and process are for. You publish from the doInBackground method, and then at some time process is called on the EDT with everything that's published so far. It's important to know that this list may contain elements from more than 1 publish call. So in this case, the SwingWorker could like like this (pseudo code):
 
Sean Keane
Ranch Hand
Posts: 582
Chrome Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Is it safe to call SwingUtilities.invokeLater() from within the doInBackground method of the SwingWorker class?
 
Darryl Burke
Bartender
Posts: 5125
11
Java Netbeans IDE Opera
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Oh, it's safe, but why on earth are you resisting the perfectly good approach that Rob Spoor has given you?
 
Sean Keane
Ranch Hand
Posts: 582
Chrome Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Darryl Burke wrote:why on earth are you resisting the perfectly good approach that Rob Spoor has given you?


I'm not. I'm using it in conjunction with it
 
Martin Vajsar
Sheriff
Posts: 3752
62
Chrome Netbeans IDE Oracle
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sean Keane wrote:
Darryl Burke wrote:why on earth are you resisting the perfectly good approach that Rob Spoor has given you?


I'm not. I'm using it in conjunction with it

If you need to perform radically different actions on the GUI thread, you might simply pass instances of Runnables to the publish() method and then call run() in the process() method. That way you'll eliminate the need for invokeLater():

I haven't ever done this, but I'd say it should work. It might not be the cleanest design, though probably still better than mixing publish()/process() with invokeLater()

I have to admit I once used invokeAndWait(), because I needed user interaction right in the middle of the processing. I don't know whether there are better alternatives to this.
 
Sean Keane
Ranch Hand
Posts: 582
Chrome Eclipse IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My particular case is that I am calling out to my business layer (using RMI) in the doInBackground method. Any network call is a potentially long running operation, that's the reason I'm using the SwingWorker.

The RMI method call could throw an error. If this happens I want to inform the user (via the GUI) that something has gone wrong. So I launch a JDialog when I catch the Exception. The launching of this JDialog is wrapped in an invokeLater.

It works . I just was not sure if it was the correct thing to do, whether there are better patterns to follow, or even if it could cause me problems.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic