*
The moose likes Swing / AWT / SWT and the fly likes Spawing operations off to separate threads Vs executing on the EDT Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Swing / AWT / SWT
Bookmark "Spawing operations off to separate threads Vs executing on the EDT" Watch "Spawing operations off to separate threads Vs executing on the EDT" New topic
Author

Spawing operations off to separate threads Vs executing on the EDT

Sean Keane
Ranch Hand

Joined: Nov 03, 2010
Posts: 581

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?


SCJP (1.4 | 5.0), OCJP (6.0), OCMJD
Sean Keane
Ranch Hand

Joined: Nov 03, 2010
Posts: 581

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

Joined: Oct 16, 2003
Posts: 1076
    
  10

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.


Ranga.
SCJP 1.4, OCMJEA/SCEA 5.0.
Martin Vajsar
Sheriff

Joined: Aug 22, 2010
Posts: 3606
    
  60

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

Joined: Oct 16, 2003
Posts: 1076
    
  10

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

Joined: Nov 03, 2010
Posts: 581

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

Joined: Aug 22, 2010
Posts: 3606
    
  60

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

Joined: Oct 16, 2003
Posts: 1076
    
  10

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

Joined: Oct 27, 2005
Posts: 19656
    
  18

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


SCJP 1.4 - SCJP 6 - SCWCD 5 - OCEEJBD 6
How To Ask Questions How To Answer Questions
Darryl Burke
Bartender

Joined: May 03, 2008
Posts: 4523
    
    5

... 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.


luck, db
There are no new questions, but there may be new answers.
Stephan van Hulst
Bartender

Joined: Sep 20, 2010
Posts: 3605
    
  14

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

Joined: Oct 16, 2003
Posts: 1076
    
  10

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

Joined: Oct 16, 2003
Posts: 1076
    
  10

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

Joined: Oct 27, 2005
Posts: 19656
    
  18

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

Joined: Nov 03, 2010
Posts: 581

Is it safe to call SwingUtilities.invokeLater() from within the doInBackground method of the SwingWorker class?
Darryl Burke
Bartender

Joined: May 03, 2008
Posts: 4523
    
    5

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

Joined: Nov 03, 2010
Posts: 581

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

Joined: Aug 22, 2010
Posts: 3606
    
  60

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

Joined: Nov 03, 2010
Posts: 581

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.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Spawing operations off to separate threads Vs executing on the EDT
 
Similar Threads
Handling threading issues when listening to model events with ModelViewPresenter
Swing and threads
What is the expected behaviour of the cursor when a dialog appears?
Handling EDT issues when listening to model events with Model View Presenter
setCursor in JApplet ???