Выход из цикла обработки событий очень простой - это просто Java.Используйте все, что вы обычно используете - исполнители, очереди и т. Д.
Например, чтобы сделать что-то «в фоновом режиме», а затем обновить графический интерфейс, вы должны сделать что-то вроде
final Executor backgroundWorker = Executors.newSingleThreadExecutor();
...
backgroundWorker.execute(()-> // from the EventLoop into the Worker
{
val result = doThatLongRunningTask();
Platform.runLater(() -> // back from the Worker to the Event Loop
{
updateUiWithResultOfLongRunningTask(result);
}
});
Как правило, я ожидаю, что поток main
будет передан в цикл обработки событий и будет использовать пользовательский исполнитель для фоновой работы (поскольку фоновая работа зависит от приложения, поэтому может потребоваться больше потоков и т. Д.).
Если по какой-либо экзотической причине (на самом деле я не могу придумать ни одной) вы хотите это наоборот:
Итак, для использования основного потока в качестве исполнителя все, что нам нужно, это:
public final class MyApp extends Application {
private static final Logger LOG = LoggerFactory.getLogger(MyApp.class);
private static final Runnable POISON_PILL = () -> {};
private final BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<>();
private final Executor backgroundWorker = this::execute;
private final Future<Void> shutdownFuture = new CompletableFuture<>();
private final Executor eventLoop = Executors.newSingleThreadExecutor();
/** Get background worker */
public Executor getBackgroundWorker() {
return backgroundWorker;
}
/** Request backgroun worker shutdown */
public Future shutdownBackgroundWorker() {
execute(POISON_PILL);
return shutdownFuture;
}
private void execute(Runnable task) {
tasks.put(task);
}
private void runWorkerLoop() throws Throwable {
Runnable task;
while ((task = tasks.take()) != POISON_PILL) {
task.run();
}
shutdownFuture.complete(null);
}
public static void main (String... args) throws Throwable {
final MyApp myApp = new MyApp(args);
LOG.info("starting JavaFX (background) ...");
eventLoop.execute(myApp::launch);
LOG.info("scheduling a ping task into the background worker...");
myApp.runLater(() -> {
LOG.info("#1 we begin in the event loop");
myApp.getBackgroundWorker().execute(() -> {
LOG.info("#2 then jump over to the background worker");
myApp.runLater(() -> {
LOG.info("#3 and then back to the event loop");
});
});
});
LOG.info("running the backgound worker (in the foreground)...");
myApp.runWorkerLoop();
}
}