I first define the ProgressMonitor:
progressMonitor = new ProgressMonitor(parent, "Starting processing ...", "", 0, maxNumberProcesses+1);
progressMonitor.setProgress(0);
and on the same thread use an ExecutorService and invokeAll() to process a list of Callables:
ExecutorService execService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); // use all available processors at startup
execService.invokeAll(callables); // wait for all tasks to complete
execService.shutdownNow(); // free thread pool resources
Each Callable is of the form:
class Callable implements Callable<List<String>>
{
public List<String> call()
{
List<String> files = doSomeStuff();
progressBarUpdate();
return files;
}
}
ie; each Callable calls progressBarUpdate():
private void progressBarUpdate()
{
if (progressMonitor != null)
{
Lock lock = new ReentrantLock();
lock.lock();
try
{
progressMonitor.increment();
}
finally
{
lock.unlock(); // release lock
}
}
}
Each doSomeStuff() has its own exception handling and if an error occurs or an exception is thrown then a null value is returned. This is why the return type is a List, and returns null in such cases. There is no crossover between the Callables and the List of files they return, they all maintain there own list of files.
I find that it works fine but occasionally it throws an InterruptedException of the form:
Disposal was interrupted:
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at java.awt.EventQueue.invokeAndWait(EventQueue.java:1263)
at java.awt.Window.doDispose(Window.java:1209)
at java.awt.Dialog.doDispose(Dialog.java:1196)
at java.awt.Window.dispose(Window.java:1147)
at javax.swing.ProgressMonitor.close(ProgressMonitor.java:311)
at javax.swing.ProgressMonitor.setProgress(ProgressMonitor.java:264)
showing that setProgress() calls close() when the monitor max is reached:
public void setProgress(int nv) {
if (nv >= max) {
close();
}
...
and close() contains numerous other non-thread safe calls.
I've modified my code so that the condition nv>=max is not satisfied and I explicitly call ProgressMonitor.close() after invokeAll(), but I'm still not convinced that such an approach is completely thread safe.
Has anyone else encountered this situation and found a rock-solid solution?
Thanks
Graham
PS. Note that ProgressMonitor is not a swing widget but does encapsulate Swing components. As a result I ensure that ProgressMonitor does not run on the EDT.
If you want to do a background task and show progress you should use a SwingWorker. The SwingWorker has a progress property that you can listen on. It ensures that the progress update is done in the Event Dispatch Thread while the task is done in a background thread.
For example:
SwingWorker<?,?> task = ...;
final JProgressBar progressBar = new JProgressBar(0, 100);
task.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer)evt.getNewValue());
}
}
});
The complete example code is in the javadoc of SwingWorker.
Looks like this is what is causing interrupt:
Worker Thread (Callable1):
close() -> doDispose() -> EventQueue.invokeAndWait() {
synchronized (lock) {
Toolkit.getEventQueue().postEvent(event);
lock.wait(); // --> (2) blocked window disposal event gets interrupted
}
}
ExecutorService.shutdownNow() :
try {
for (Worker w : workers) {
w.interruptNow(); // (1) --> Setting interrupt flag
}
} catch (SecurityException se) { // Try to back out
runState = state;
// tryTerminate() here would be a no-op
throw se;
}
Functionally looks like, when your progress-monitor completes (or reached max), before the event is dispatched (may or may not occur depends how busy the eventQ is), service shutdown itself.
Conceptually I don't see any specific issue within your code, but its mainly implicit thread-communication by your executor-service to AWT.EventQueue.
You can either consume InterruptedException around progressMonitor.increment(); or use ExecutorService.awaitTermination before calling shutdownNow.
Related
I've been trying to make a binary semaphore that will be able to safely block execution of a method running on the event dispatch thread (EDT) without actually blocking the thread from handling more events. This may initially seem impossible, but Java has some built-in functionality related to this, but I can't quite get it to work.
Use Case
Currently, if you show a modal swing dialog from the EDT, it will appear to block the EDT (because your method that displayed the modal dialog will not continue onto the next line until the dialog is closed), but really there's some under-the-hood magic that makes the EDT enter a new event loop which will continue to dispatch events until the modal dialog is closed.
My team currently has applications that are very slowly migrating from swing to JavaFX (a somewhat tricky transition) and I wanted to be able to display modal JavaFX dialogs from the AWT event dispatch thread in the same way that swing modal dialogs can be shown. It seemed like having some sort of EDT-safe semaphore would meet this use case and likely come in handy for other uses down the road.
Approach
java.awt.EventQueue.createSecondaryLoop() is a method that creates a SecondaryLoop object, which you can then use to kick off a new event handling loop. When you call SecondaryLoop.enter(), the call will block while it processes a new event loop (note that the call blocks, but the thread is not blocked because it is continuing in an event processing loop). The new event loop will continue until you call SecondaryLoop.exit() (that's not entirely true, see my related SO question).
So I've created a semaphore where a blocking call to acquire results in waiting on a latch for a normal thread, or entering a secondary loop for the EDT. Each blocking call to acquire also adds an unblocking operation to be called when the semaphore is freed (for a normal thread, it just decrements the latch, for the EDT, it exits the secondary loop).
Here is my code:
import java.awt.EventQueue;
import java.awt.SecondaryLoop;
import java.awt.Toolkit;
import java.util.Stack;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
#SuppressWarnings("serial")
public class EventDispatchThreadSafeBinarySemaphore extends Semaphore{
/** Operations used to unblock threads when a semaphore is released.
* Must be a stack because secondary loops have to be exited in the
* reverse of the order in which they were entered in order to unblock
* the execution of the method that entered the loop.
*/
private Stack<Runnable> releaseOperations = new Stack<>();
private boolean semaphoreAlreadyAcquired = false;
public EventDispatchThreadSafeBinarySemaphore() {
super(0);
}
#Override
public boolean isFair() {
return false;
}
#Override
public void acquire() throws InterruptedException {
Runnable blockingOperation = () -> {};
synchronized(this) {
if(semaphoreAlreadyAcquired) {
//We didn't acquire the semaphore, need to set up an operation to execute
//while we're waiting on the semaphore and an operation for another thread
//to execute in order to unblock us when the semaphore becomes available
if(EventQueue.isDispatchThread()) {
//For the EDT, we don't want to actually block, rather we'll enter a new loop that will continue
//processing AWT events.
SecondaryLoop temporaryAwtLoop = Toolkit.getDefaultToolkit().getSystemEventQueue().createSecondaryLoop();
releaseOperations.add(() -> temporaryAwtLoop.exit());
blockingOperation = () -> {
if(!temporaryAwtLoop.enter()) {
//I don't think we'll run into this, but I'm leaving this here for now for debug purposes
System.err.println("Failed to enter event loop");
}
};
}
else {
//Non-dispatch thread is a little simpler, we'll just wait on a latch
CountDownLatch blockedLatch = new CountDownLatch(1);
releaseOperations.add(() -> blockedLatch.countDown());
blockingOperation = () -> {
try {
blockedLatch.await();
} catch (InterruptedException e) {
//I'll worry about handling this better once I have the basics figured out
e.printStackTrace();
}
};
}
}
else {
semaphoreAlreadyAcquired = true;
}
}
//This part must be executed outside of the synchronized block so that we don't block
//the EDT if it tries to acquire the semaphore while this statement is blocked
blockingOperation.run();
}
#Override
public void release() {
synchronized(this) {
if(releaseOperations.size() > 0) {
//Release the last blocked thread
releaseOperations.pop().run();
}
else {
semaphoreAlreadyAcquired = false;
}
}
}
}
And here is my relevant JUnit test code (I apologize for the large size, this is the smallest minimum verifiable example I've been able to come up with so far):
public class TestEventDispatchThreadSafeBinarySemaphore {
private static EventDispatchThreadSafeBinarySemaphore semaphore;
//See https://stackoverflow.com/questions/58192008/secondaryloop-enter-not-blocking-until-exit-is-called-on-the-edt
//for why we need this timer
private static Timer timer = new Timer(500, null);
#BeforeClass
public static void setupClass() {
timer.start();
}
#Before
public void setup() {
semaphore = new EventDispatchThreadSafeBinarySemaphore();
}
#AfterClass
public static void cleanupClass() {
timer.stop();
}
//This test passes just fine
#Test(timeout = 1000)
public void testBlockingAcquireReleaseOnEDT() throws InterruptedException {
semaphore.acquire();
CountDownLatch edtCodeStarted = new CountDownLatch(1);
CountDownLatch edtCodeFinished = new CountDownLatch(1);
SwingUtilities.invokeLater(() -> {
//One countdown to indicate that this has begun running
edtCodeStarted.countDown();
try {
semaphore.acquire();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//This countdown indicates that it has finished running
edtCodeFinished.countDown();
});
//Ensure that the code on the EDT has started
edtCodeStarted.await();
assertEquals("Code on original AWT event thread should still be blocked", 1, edtCodeFinished.getCount());
//Ensure that things can still run on the EDT
CountDownLatch edtActiveCheckingLatch = new CountDownLatch(1);
SwingUtilities.invokeLater(() -> edtActiveCheckingLatch.countDown());
//If we get past this line, then we know that the EDT is live even though the
//code in the invokeLater call is blocked
edtActiveCheckingLatch.await();
assertEquals("Code on original AWT event thread should still be blocked", 1, edtCodeFinished.getCount());
semaphore.release();
//If we get past this line, then the code on the EDT got past the semaphore
edtCodeFinished.await();
}
//This test fails intermittently, but so far only after the previous test was run first
#Test(timeout = 10000)
public void testConcurrentAcquiresOnEDT() throws InterruptedException {
int numThreads =100;
CountDownLatch doneLatch = new CountDownLatch(numThreads);
try {
semaphore.acquire();
//Queue up a bunch of threads to acquire and release the semaphore
//as soon as it becomes available
IntStream.range(0, numThreads)
.parallel()
.forEach((threadNumber) ->
SwingUtilities.invokeLater(() -> {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
semaphore.release();
//Count down the latch to indicate that the thread terminated
doneLatch.countDown();
}
})
);
semaphore.release();
doneLatch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
The Problem
testConcurrentAcquiresOnEDT will sometimes pass and sometimes fail. I believe that I know why. I dug into the Java source code and in WaitDispatchSupport (the concrete implementation of SecondaryLoop), the loop basically continues dispatching events until a flag called keepBlockingEDT is cleared. It will check this between events. When I call exit, it will clear that flag and send an event to wakeup the event queue in case it was waiting for more events. However, it will not cause the enter() method to immediately exit (and I don't think there's anyway it possibly could).
So here's how the deadlock results:
The main thread acquires the semaphore
The EDT thread tries to acquire the semaphore, but it is already acquired, so it:
Creates a new secondary loop
Creates a Runnable that will exit the new secondary loop and pushes it to the releaseOperations stack
Enters the secondary loop, causing execution to block (note that this last step is by necessity outside of the synchronized block
The main thread releases the semaphore, which causes the following to happen:
The releaseOperations stack is popped and it calls exit on the secondary loop
The exit call, sets the keepBlockingEDT flag for that secondary loop to be set to false
Back in the EDT, it just got done checking the keepBlockingEDT flag (right before it was set to false) and it is fetching the next event.
It turns out that the next event is another runnable that blocks on the semaphore, so it tries to acquire it
This creates another SecondaryLoop on top of the original SecondaryLoop and enters it
At this point, the original SecondaryLoop has already had it's keepBlockingEDT flag cleared and it would be able to stop blocking, except that it is currently blocked running the second SecondaryLoop. The second SecondaryLoop won't ever have exit called on it because no one actually has the semaphore acquired right now, therefore we block forever.
I've been working on this for a few days and every idea I come up with is a dead end.
I believe that I have a possible partial solution, which is to simply not allow more than one thread to be blocked on the semaphore at a time (if another thread tries to acquire it, I'll just throw an IllegalStateException). I could still have multiple secondary loops going if they each use their own semaphore, but each semaphore would create at most 1 secondary loop. I think this would work and it will meet my most likely use case just fine (because mostly I just want to show a single JavaFX modal dialog from the event thread). I just wanted to know if anyone else had other ideas because I feel like I got close to making something pretty cool, but it just doesn't quite work.
Let me know if you have any ideas. And "I'm pretty sure this is impossible and here's why..." is an acceptable answer as well.
Using a Semaphore is most likely not the correct approach. What you want is to enter nested event loops, not use blocking mechanisms. From reading the API it also appears you are over-complicating things. Again, all you need is to enter a nested event loop on one UI thread and then exit that loop once the other UI thread has completed its work. I believe the following meets your requirements:
import java.awt.EventQueue;
import java.awt.SecondaryLoop;
import java.awt.Toolkit;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import javafx.application.Platform;
import javax.swing.SwingUtilities;
public class Foo {
public static <T> T getOnFxAndWaitOnEdt(Supplier<? extends T> supplier) {
Objects.requireNonNull(supplier, "supplier");
if (!EventQueue.isDispatchThread()) {
throw new IllegalStateException("current thread != EDT");
}
final SecondaryLoop loop = Toolkit.getDefaultToolkit()
.getSystemEventQueue()
.createSecondaryLoop();
final AtomicReference<T> valueRef = new AtomicReference<>();
Platform.runLater(() -> {
valueRef.set(supplier.get());
SwingUtilities.invokeLater(loop::exit);
});
loop.enter();
return valueRef.get();
}
public static <T> T getOnEdtAndWaitOnFx(Supplier<? extends T> supplier) {
Objects.requireNonNull(supplier, "supplier");
if (!Platform.isFxApplicationThread()) {
throw new IllegalStateException(
"current thread != JavaFX Application Thread");
}
final Object key = new Object();
final AtomicReference<T> valueRef = new AtomicReference<>();
SwingUtilities.invokeLater(() -> {
valueRef.set(supplier.get());
Platform.runLater(() -> Platform.exitNestedEventLoop(key, null));
});
Platform.enterNestedEventLoop(key);
return valueRef.get();
}
}
The Platform#enterNestedEventLoop and Platform#exitNestedEventLoop methods were added in JavaFX 9 though there are equivalent internal methods in JavaFX 8. The reason AtomicReference is used is because local variables must be final or effectively final when used inside a lambda expression. However, due to the way the separate threads are notified I don't believe the volatility semantics provided by the #get() and #set(T) methods of AtomicReference is strictly needed but I've used those methods just in case.
Here's an example of using the above to show a modal JavaFX dialog from the Event Dispatch Thread:
Optional<T> optional = Foo.getOnFxAndWaitOnEdt(() -> {
Dialog<T> dialog = new Dialog<>();
// configure dialog...
return dialog.showAndWait();
});
The above utility methods are for communicating from the Event Dispatch Thread to the JavaFX Application Thread and vice versa. This is why entering a nested event loop is necessary, otherwise one of the UI threads would have to block and that would freeze the associated UI. If you're on a non-UI thread and need to run an action on a UI thread while waiting for the result the solution is much simpler:
// Run on EDT
T result = CompletableFuture.supplyAysnc(/*Supplier*/, SwingUtilities::invokeLater).join();
// Run on FX thread
T result = CompletableFuture.supplyAsync(/*Supplier*/, Platform::runLater).join();
The call to join() will block the calling thread so be sure not to call the method from either of the UI threads.
I have a javafx app, and I want to surround some code with "waiting" feature. So my code can be Runnable and Callable. The problem is getting result from Callabe. I tried to play with:
wait()/notify()
Platform.runLater
creating daemon threads by hands
Service
after reading some articles here, but it doesn't help.
How I want to call it:
final String a =
CommonHelper.showWaiting(() -> {
System.out.println("test");
return "test2";
});
That's how I work with Runnable:
public static void showWaiting(Runnable runnable) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
try {
executorService.submit(new WaitingTask<>(executorService.submit(runnable)));
} finally {
executorService.shutdown();
}
}
And my WaitingTask is:
public class WaitingTask<T> extends Task<Void> {
#Getter
private final Future<T> future;
public WaitingTask(Future<T> future) {
this.future = future;
}
#Override
protected Void call() {
showSpinner();
while (true) {
if (future.isDone()) {
hideSpinner();
break;
}
}
}
return null;
}
}
That works awesome - my app shows waiting spinner, and task runns in separate thread.
So I try to work the same way with Callable to get the result:
public static <T> T showWaiting(Callable<T> callable) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
try {
FutureTask<T> task = new FutureTask<>(callable);
Future<T> result = (Future<T>) executorService.submit(task);
executorService.submit(new WaitingTask<>(result));
return result.get();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
executorService.shutdown();
}
}
but I can not see waiting spinner, maybe the app's main thread waits for result.get(); and the app freezes. How can I fix it?
There are a few things you are doing incorrectly:
You wrap your Callable in a FutureTask before submitting it to an ExecutorService. You don't need to do this, and in fact you shouldn't do this. Instead, just submit your Callable directly and you will get a Future in return.
Future<T> future = executor.submit(callable);
If you're using the core implementation of ExecutorService the returned Future will be a FutureTask anyway. Not that you should care—the only important thing is that its a Future. Note the same goes for Runnables; just submit them directly, don't wrap them in a FutureTask first.
You're submitting your Callable, getting a Future, and wrapping said Future in a Task...and then submitting your Task. This means you will have two tasks for every one you want to execute. Depending on how your ExecutorService is configured, this equates to using two threads per task.
You should be using your Task as if it was your Callable. Do the work inside the Task#call() method and return the result. Then only submit the Task, don't wrap it in anything first.
executor.execute(task); // Don't need the Future here, just use "execute"
If you want the result of the Task you can register callbacks (see this). The class is designed to invoke these callbacks on the JavaFX Application Thread.
task.setOnSucceeded(event -> {
T value = task.getValue();
// do something with value...
});
Note that Task extends FutureTask. This seems contradictory to point 1, but that's just how it is. Personally, I wouldn't have designed the class that way—it ends up wrapping the Task in another Future (likely FutureTask) when executed using the Executor Framework.
This is related to number 2; if you fix that issue then this issue inherently goes away.
You are spin waiting for the wrapped Future to complete. This is a waste of resources. The Future interface has a get() method that will block the calling thread until said Future is done. If the Future completes normally you'll get the value in return, else if it completes exceptionally an ExecutionException will be thrown. The third option is the calling thread is interrupted and an InterruptedException is thrown.
If the method names "showSpinner" and "hideSpinner" aren't misleading, you are updating the UI from a background thread. Never update the UI from a thread other than the JavaFX Application Thread. Now, you could wrap those calls in a Platform.runLater action, but you could also use the properties/callbacks of the Task. For instance, you could listen to the running property to know when to show and hide your spinner.
Taking all that into account, your example should look more like:
// Doesn't have to be an anonymous class
Task<String> task = new Task<>() {
#Override
protected String call() {
System.out.println("test");
return "test2";
}
});
task.runningProperty().addListener((obs, wasRunning, isRunning) -> {
if (isRunning) {
showSpinner();
} else {
hideSpinner();
}
});
task.setOnSucceeded(event -> {
String a = task.getValue();
// Do something with value.
});
executorService.execute(task);
For more information, I suggest reading:
Concurrency in JavaFX
Documentation of javafx.concurrent.Worker
Documentation of javafx.concurrent.Task (and Worker's other implementations)
Possibly a tutorial on Java's Executor Framework.
Thanks all for help, especially #Slaw and #kendavidson
Finally I've found a simple and perfect solution here:
Modal JaxaFX Progress Indicator running in Background
Maybe I'll post my full generic-based example here, based on this principles
I have a method called action() that deploys three threads. Each deployed thread or worker thread falls into a while loop based on a single instance variable of type boolean being true, for example boolean doWork = true, each thread will have a while(doWork){} loop.
When a thread finishes the job will set the doWork to false stopping all the threads from looping. Then I would like to be able to somehow let the main thread recall the action() method to redeploy the threads to do another job. (If I use one of the worker threads to call the action() method is it OK ?) will the worker thread terminate once it calls the action() method and somehow die ?
I limited the example to two threads for simplicity
Thanks
class TestThreads{
boolean doWork = true;
void action(){
ThreadOne t1 = new ThreadOne();
ThreadTwo t2 = new ThreadTwo();
}
//innerclasses
class ThreadOne implements Runnable{
Thread trd1;
public ThreadOne(){//constructor
if(trd1 == null){
trd1 = new Thread(this);
trd1.start();
}
}
#Override
public void run(){
while(doWork){
//random condition
//would set doWork = false;
//stop all other threads
}
action();//is the method in the main class
}
}
class ThreadTwo implements Runnable{
Thread trd2;
public ThreadTwo(){//constroctor
if(trd2 == null){
trd2 = new Thread(this);
trd2.start();
}
}
#Override
public void run(){
while(doWork){
//random condition
//would set doWork = false;
//stop all other threads
}
action();//is the method in the main class
}
}
}
How about this implementation:
Declare a class member doWork, a counter for currently active threads and a synchronization object:
private volatile boolean doWork = true;
private AtomicInteger activeThreads;
private Object locker = new Object();
In main:
while(true) {
// call action to start N threads
activeThreads = new AtomicInteger(N);
action(N);
// barrier to wait for threads to finish
synchronized(locker) {
while(activeThreads.get() > 0) {
locker.wait();
}
}
}
In thread body:
public void run() {
while(doWork) {
...
// if task finished set doWork to false
}
// signal main thread that I've finished
synchronized(locker) {
activeThreads.getAndDecrement();
locker.notify();
}
}
Skeleton code
// OP said 3 threads...
ExecutorService xs = Executors.newFixedThreadPool(3);
...
// repeat the following as many times as you want...
// this is the setup for his 3 threads - as Callables.
ArrayList<Callable<T>> my3Callables = new ArrayList<Callable<T>>();
my3Callables.add(callable1);
my3Callables.add(callable2);
my3Callables.add(callable3);
try {
List<Future<T>> futures = xs.invokeAll(my3Callables );
// below code may not be needed but is useful for catching any exceptions
for (Future<T> future : futures) {
T t = future.get();
// do something with T if wanted
}
}
catch (ExecutionException ee) {
// do something
}
catch (CancellationException ce) {
// do something
}
catch (InterruptedException ie) {
// do something
}
I'll expand my comment (even though #babernathy as added this to his answer).
Typically where you have a pool of threads where you want to execute some piece of work, and you have a main thread managing the items of work that you want done, the ExecutorService provides the ideal framework.
In your main object, you can create an instance of the service (with the number of threads you want), and then as you generate a piece of work, submit it to the service, and the service will pick the next available thread from the pool and execute it.
If you have a dependency on knowing if particular pieces of work have completed, you can use something like a CountDownLatch to track when threads have completed their work. My point, there are quite a few existing frameworks for this kind of activity, no need to go through the pain all over again...
It's a little difficult to give you an exact solution without any code. It sounds like you are describing the producer/consumer pattern where you give a set of worker threads some tasks and when they are done, you give them more.
Here is a web page that does an OK job of describing what to do.
Also take a look at the ExecutorService that allows you to submit Runnables and have them executed.
A simple solution is to have the main thread sleep:
static boolean doWork = true; // better to use AtomicBoolean
void action() {
// start workers, which eventually set doWork = false
while (doWork) {
Thread.sleep(/**time in millis**/); // main thread waits for workers
}
// logic to run action() again, etc.
}
The main thread starts the workers, periodically waking up to check if they've terminated. Since the main thread is an "arbiter", it probably shouldn't die just to be resurrected by one of its children.
Reference
Thread.sleep()
AtomicBoolean
In a web controller, I have a parent thread that receives requests. Some requests take a long time to process. To prevent clients from timing out, I set up the parent thread to send back a byte every 2 seconds while a child thread is doing the time-consuming part of the operation.
I want to make sure I'm accounting for all possible cases of the child thread dying, but I also don't want to put in any extraneous checks.
Here is the parent thread:
// This is my runnable class
ProcessorRunnable runnable = new ProcessorRunnable(settings, Thread.currentThread());
Thread childThread = new Thread(runnable);
childThread.start();
boolean interrupted = false;
while (!runnable.done) { // <-- Check in question
outputStream.write(' ');
outputStream.flush();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// If the runnable is done, then this was an expected interrupt
// Otherwise, remember the interruption and re-interrupt after processing is done
// Or with self so that a later expected interrupt won't clear out an earlier unexpected one
interrupted = interrupted || !runnable.done;
}
}
if (runnable.runtimeException != null) {
LOG.error("Propagating runtime exception from thread");
throw runnable.runtimeException;
}
// ... Further processing on the results provided by the child thread
And here's ProcessorRunnable:
private volatile boolean done;
private volatile Result result;
private volatile RuntimeException runtimeException;
// ...
public void run() {
done = false;
try {
result = myService.timeConsumingOperation(settings);
} catch (RuntimeException e) {
runtimeException = e;
} finally {
done = true;
parentThread.interrupt();
}
}
My question is, would adding && Thread.isAlive() check in the parent thread's main loop buy me anything?
It seems that setting done = true in the finally block should do the trick, but are there some cases where this child thread could die without notifying the parent?
The finally in the child thread will always execute before it finishes. Even if that thread is interrupted or stopped, this happens via an exception that bubbles up the call stack and triggers all finallys. So, done will always be true if the child thread is interrupted.
For background tasks like this you may want to use an ExecutorService instead of raw threads. You can submit a Runnable to an ExecutorService and just call get() on the returned future to block until it is done. If you want to print out spaces while you are waiting, you can use a loop, calling the get() version with a timeout.
I'm writing an application that executes its file menu actions using SwingWorker. Every called method returns a boolean value that tells, whether the operation was successfully executed or not.
At the moment I'm using busy waiting for the result, like this:
public boolean executeOperation() {
final SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
#Override
protected Boolean doInBackground() throws Exception {
// ..
if (aborted) {
return false;
}
// ..
return true;
}
};
worker.execute();
// busy wait
while (!worker.isDone())
;
try {
return worker.get().booleanValue();
} catch (Exception e) {
// handle exceptions ..
return false;
}
}
Is there a less polling-intense way of solving this?
Using worker.get() directly wouldn't work, as it blocks the EDT, waiting for the task to finish - meaning even the dialogs I open from within the SwingWorker wouldn't get painted.
EDIT: If possible, I would like to avoid that the method (or the worker) to communicate their result asynchronously. I'm implementing several short methods (file -> open, new, close, save, save as, exit) that rely on each other (i. e. when the trying to exit, exit calls close, close might call save, save might call save as). Solving this asynchronously seems to make the code much more complicated.
The point of the SwingWorker is precisely to launch some task in the background and don't block the EDT. Either you want something synchronous, and the EDT will be blocked whatever you try, or you want something asynchronous, and the background task should update its status using the publish method of the SwingWorker.
You could display a blocking modal dialog with a progress bar while the task is running, and hide it once the task completes.
The alternative is to block for some time, hoping the task will be quick to finish, and then backup to an asynchronous way of doing. This can be done using the get method taking a timeout as argument.
You could use an asynchronous paradigm. Look at Observer / Observable and use the job to transfer the result back to the object which is currently doing the polling.
Using worker.get() directly wouldn't work, as it blocks the EDT, waiting for the task to finish - meaning even the dialogs I open from within the SwingWorker wouldn't get painted.
They don't with the current code either. Your busy wait blocks the EDT as much as calling worker.get() does - there is only one event dispatch thread, and the dialogs in the SwingWorker are just as blocked if that thread is spinning in a loop or awaiting a lock. The problem here is that if a method runs on the EDT, it simply can't return a value from an asynchronous operation (without hogging the EDT) to its caller.
The correct way to react to completed async processing is overriding the done() method in SwingWorker.
Also check out http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html for more info.
One way as mentioned by several folks above is to override the SwingWorker's done method. However if for some reason you want the post SwingWorker code outside of the SwingWorker and in the calling code, you can take advantage of SwingWorker's property change support. Simply add a PropertyChangeListener to the SwingWorker and listen for the state property which has a property name of "state". You can then extract the SwingWorker's state with its getState() method. When it is done it will return the DONE value of the SwingWorker.StateValue enum. For example (from an answer I've given in another thread here on SO):
if (turn == white) {
try {
final SwingWorker<Move, Void> mySwingWorker = new SwingWorker<Move, Void>() {
#Override
protected Move doInBackground() throws Exception {
Engine e = new Engine(); // Engine is implemented by runnable
e.start();
Move m = e.getBestMove(board);
return m;
}
};
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (StateValue.DONE == mySwingWorker.getState()) {
try {
Move m = mySwingWorker.get();
// TODO: insert code to run on the EDT after move determined
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
});
mySwingWorker.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
I ran into a similar problem when I wanted a function to return a value that would be calculated in a swing worker. I didn't want to simply get that thread to block the EDT. I also didn't want it to block. So I used a semaphore like this:
public boolean executeOperation() {
final Semaphore semaphore = new Semaphore(1);
semaphore.acquire(1); // surround by try catch...
final SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
#Override
protected Boolean doInBackground() throws Exception {
// ..
if (aborted) {
semaphore.release();
return false;
}
// ..
semaphore.release();
return true;
}
};
worker.execute();
try {
semaphore.tryAcquire(1, 600, TimeUnit.SECONDS); // awakes when released or when 10 minutes are up.
return worker.get().booleanValue(); // blocks here if the task doesn't finish in 10 minutes.
} catch (Exception e) {
// handle exceptions ..
return false;
}
}
I guess this is not ideal for all situations. But I thought it was an alternative approach that was very useful for me.