I've updated this question to include source code of a Java implementation, using the suggested SwingWorker class, to accomplish the same result as the Objective-C example. Hopefully this will be of aid to future adventurers.
Document myDoc = ...;
Model myModel = ...;
SwingWorker analyzeDocument = new SwingWorker<Dictionary, Void>() {
@Override
public Dictionary doInBackground() {
return myDoc.analyze();
}
@Override
public void done() {
try {
stats = get();
myModel.setDict(stats);
myModel.setNeedsDisplay(true);
} catch(InterruptedException ex) {
// log
} catch(ExecutionException ex) {
// log
}
}
};
analyzeDocument.execute();
I'm inexperienced when it comes to concurrent programming and I was hoping someone may be able to explain to me how I can achieve this.
In Objective-C (with GCD), you're able to do something like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
NSDictionary *stats = [myDoc analyze];
dispatch_async(dispatch_get_main_queue(), ^{
[myModel setDict:stats];
[myStatsView setNeedsDisplay:YES];
[stats release];
});
});
This code will execute [myDoc analyze]
in the background thread, following a callback function to update the UI which will executed in the main thread. In other words, the background thread sends an interrupt to the main thread, adding the anonymous function to the main thread's queue to be invoked. Obviously I won't be able to use anonymous functions in Java, but that's beside the point.
I am interested in doing something to this effect in Java. I have a Runnable
object which does a bunch of stuff in the file system. When it finishes, I want to update the UI accordingly.
In an effort to not hang the main thread while doing this (ie: backgroundThread.join();
), I've set the background thread to execute a callback function to update the UI. But this isn't a good idea, I don't want a non-GUI thread updating the GUI.
Some other ideas I've thought of is polling, but that seems like throwing cycles out the window. By the same judgement, using Futures doesn't seem to be the answer either. This all seems to defeat the purpose of an asynchronous action.
The only other thing I can think of is using SwingUtilities.invokeLater
from the background thread and using it to update the GUI. But I'm curious in which thread this would be executed.
Maybe my perception is just warped, but this seems like it would be a pretty big part to leave out. Am I just trying to go about this the wrong way?
Have you looked into creating and using a SwingWorker
object? This allows you to easily run code in a thread background to the event thread, and in fact is a Future object as well and so it can return a result, and you can use this result in its done()
method to update the GUI on the event thread. You can even do calls on the Swing event thread in the middle of its run via the publish
/process
method pair.
For more on this, please check out: Concurrency in Swing
If you use Callable<V>
instead of Runnable
, you can return a value.
Also, take a look at class Executors
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With