Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaFX-从gui接收事件后返回主线程_Java_Multithreading_Javafx - Fatal编程技术网

JavaFX-从gui接收事件后返回主线程

JavaFX-从gui接收事件后返回主线程,java,multithreading,javafx,Java,Multithreading,Javafx,我正在编写一个JavaFX应用程序,并意识到在FX线程上发生的事情太多了。根本原因之一是gui事件,如按钮单击,会在FX线程上产生后端操作。事实上,在收到事件后,我们就在FX线程上,所以任何进一步的呼叫都会留在上面。有没有办法简单地返回主应用程序线程,然后在需要时返回Platform.runLater,或者我必须使用例如RX或一些executor服务来处理它 谢谢退出事件循环的方法非常简单-它只是Java。使用您通常使用的任何东西-执行器、队列等 例如,要在“后台”完成某项工作,然后更新GUI,

我正在编写一个JavaFX应用程序,并意识到在FX线程上发生的事情太多了。根本原因之一是gui事件,如按钮单击,会在FX线程上产生后端操作。事实上,在收到事件后,我们就在FX线程上,所以任何进一步的呼叫都会留在上面。有没有办法简单地返回主应用程序线程,然后在需要时返回Platform.runLater,或者我必须使用例如RX或一些executor服务来处理它


谢谢

退出事件循环的方法非常简单-它只是Java。使用您通常使用的任何东西-执行器、队列等

例如,要在“后台”完成某项工作,然后更新GUI,您可以执行以下操作

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();
    }
}
公共最终类MyApp扩展应用程序{
私有静态最终记录器LOG=LoggerFactory.getLogger(MyApp.class);
私有静态最终可运行毒药丸=()->{};
private final BlockingQueue tasks=新建LinkedBlockingQueue();
private final Executor backgroundWorker=this::execute;
private final Future shutdownFuture=新的CompletableFuture();
private final Executor eventLoop=Executors.newSingleThreadExecutor();
/**获取后台工作人员*/
公共执行器getBackgroundWorker(){
返回后台工作人员;
} 
/**请求背景工作程序关闭*/
公共未来关闭BackgroundWorker(){
执行(毒药丸);
回归未来;
}
私有void执行(可运行任务){
任务。放置(任务);
}
私有void runWorkerLoop()抛出可丢弃的{
可运行任务;
而((task=tasks.take())!=毒药丸){
task.run();
}
shutdownFuture.complete(空);
}
publicstaticvoidmain(字符串…参数)抛出Throwable{
最终MyApp MyApp=新的MyApp(args);
LOG.info(“启动JavaFX(后台)…”;
execute(myApp::launch);
LOG.info(“将ping任务安排到后台工作程序…”);
myApp.runLater(()->{
LOG.info(“#1我们从事件循环开始”);
myApp.getBackgroundWorker().execute(()->{
LOG.info(“#2然后跳到后台工作程序”);
myApp.runLater(()->{
LOG.info(“#3,然后返回事件循环”);
});
});
});
LOG.info(“运行后台工作程序(在前台)…”;
myApp.runWorkerLoop();
}
}

退出事件循环的方法非常简单——它只是Java。使用您通常使用的任何东西-执行器、队列等

例如,要在“后台”完成某项工作,然后更新GUI,您可以执行以下操作

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();
    }
}
公共最终类MyApp扩展应用程序{
私有静态最终记录器LOG=LoggerFactory.getLogger(MyApp.class);
私有静态最终可运行毒药丸=()->{};
private final BlockingQueue tasks=新建LinkedBlockingQueue();
private final Executor backgroundWorker=this::execute;
private final Future shutdownFuture=新的CompletableFuture();
private final Executor eventLoop=Executors.newSingleThreadExecutor();
/**获取后台工作人员*/
公共执行器getBackgroundWorker(){
返回后台工作人员;
} 
/**请求背景工作程序关闭*/
公共未来关闭BackgroundWorker(){
执行(毒药丸);
回归未来;
}
私有void执行(可运行任务){
任务。放置(任务);
}
私有void runWorkerLoop()抛出可丢弃的{
可运行任务;
而((task=tasks.take())!=毒药丸){
task.run();
}
shutdownFuture.complete(空);
}
publicstaticvoidmain(字符串…参数)抛出Throwable{
最终MyApp MyApp=新的MyApp(args);
LOG.info(“启动JavaFX(后台)…”;
execute(myApp::launch);
LOG.info(“将ping任务安排到后台工作程序…”);
myApp.runLater(()->{
LOG.info(“#1我们从事件循环开始”);
myApp.getBackgroundWorker().execute(()->{
LOG.info(“#2然后跳到后台工作程序”);
myApp.runLater(()->{
LOG.info(“#3,然后返回事件循环”);
});
});
});
LOG.info(“运行后台工作程序(在前台)…”;
myApp.runWorkerLoop();
}
}
Read。如果查看,您将看到:“启动方法在应用程序退出[…]之前不会返回”。调用
launch
的线程只需创建JavaFX启动器线程,然后等待
CountDownLatch
。JavaFXLauncher线程初始化工具箱,调用
Application.init
,然后将控制权交给JavaFX应用程序线程;然后,启动器线程也会等待。鉴于此,您通常不能在JavaFX.Read中使用主线程