This question seems similar to:
And the runAndWait
code from your question looks very similar to Sarcan's answer, which is this:
final FutureTask query = new FutureTask(new Callable() {
@Override
public Object call() throws Exception {
return queryPassword();
}
});
Platform.runLater(query);
System.out.println(query.get());
In comments on other answers I notice you are also concerned about Exception handling. You will notice that FutureTask has logic to setException()
:
Causes this future to report an ExecutionException with the given throwable as its cause, unless this future has already been set or has been cancelled.
This method is invoked internally by the run()
method upon failure of the computation.
As the internal implementation invokes the setException
call, you don't need to explicitly invoke setException
. Any uncaught exception thrown in the context of the FutureTask will be set in that FutureTask and you can interpret it via catching an ExecutionException
from your future.get()
call.
// non-JavaFX thread code...
Future<Void> future = new FutureTask<>(() -> {
// work to be done on the JavaFX thread...
return null;
}
});
// do the work on the JavaFX thread.
Platform.runLater(future);
try {
// await completion of the work on the JavaFX thread.
future.get();
} catch (InterruptedException ex) {
// restore the interrupt status (see the linked Goetz article).
Thread.currentThread().interrupt();
} catch (ExecutionException ex) {
// exception handling logic for an exception occurring
// in the body of the FutureTask here.
}
In the sample above I have a Future<Void>
as I am not interested in passing any data result from the Future call. If I were interested in getting a result, then I could use Future<SomeObjectType>
and have SomeObjectType result = future.get()
. In situations like this I like to use immutable objects as much as possible (for example for SomeObjectType
), though it is not strictly necessary for the future.get()
scenario as that essentially is accessing objects in sequence rather than in parallel across threads.
If you wanted to re-throw the exception that occurred on the JavaFX application thread on the non-JavaFX thread, then you could do this:
} catch (ExecutionException ex) {
throw ex.getCause();
}
The following information is for different thread based interactions with JavaFX (or Java in general) and does not directly relate to the question, so it can be ignored for the specifics of answering the question, it merely serves as background info.
Some background info: I find a really excellent on implementation of tasks in Java to be Brian Goetz's article:
Opposite interaction: The example given above relates to invoking tasks on the JavaFX application thread from another thread and awaiting their completion. If you have the opposite situation where you want to invoke a Task on another thread instead of the JavaFX thread, then you would use a JavaFX Task. In such a case you don't want the JavaFX thread to await completion of the non-JavaFX task as you should never pause or suspend the JavaFX thread (instead the Task call must be executed concurrently, how to do this is explained in the linked Task Javadoc).
There are mechanisms for interacting between the background thread and the JavaFX UI detailed in the related (but different) question: