当前位置: 首页 > 知识库问答 >
问题:

如何等待多个服务完成?

江亮
2023-03-14

我正在运行这样的多个服务:(例如,在多个线程中读取文件)

for (int i = 0; i < 3; i++) {
        ReadService readService = new ReadService();
        readService.start();
}

//wait until all services have been completed
System.out.println("All services done!");

ReadService是一个扩展Service类的类,它正在做一些事情,比如读取文件。它是从另一个线程调用的,该线程不是JavaFX应用程序线程。

我如何等到所有这些服务完成后再调用系统。出来println

可复制的例子:

import javafx.application.Application;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.stage.Stage;

public class HelloApplication extends Application {

    @Override
    public void start(Stage stage) {
        for (int i = 0; i < 3; i++) {
            ReadService readService = new ReadService();
            readService.start();
        }
        // wait until all services have been completed
        System.out.println("Services done");
        // continue with some other code, for example check the read file on anything
    }

    public static void main(String[] args) {
        launch();
    }
}

class ReadService extends Service<Boolean> {

    @Override
    protected Task<Boolean> createTask() {
        return new Task<>() {
            @Override
            protected synchronized Boolean call() throws Exception {
                // do something, for example read a file
                System.out.println("wait...");
                wait(5000);
                System.out.println("waiting done");
                return null;
            }
        };
    }
}

共有1个答案

鞠嘉志
2023-03-14

您正在从FX Application Thread(这是执行start()方法的地方)启动服务,并且您不能阻止该线程。所以一种方法是为完成的服务数量创建一个计数器,并在它达到零时做出响应。

请注意,这里的所有新内容(创建和更新servicesPending属性,以及在服务完成时执行的代码)都在FX Application Thread上执行,所以如果您在服务完成时更新UI,这种方法是合适的...

@Override
public void start(Stage stage) {

    int numServices = 3 ;

    IntegerProperty servicesPending = new SimpleIntegerProperty(numServices);

    servicesPending.addListener((obs, oldValue, newValue) -> {
         if (newValue == 0) {
             // code to execute when all services are complete
             System.out.println("Services done");
         }
    });

    for (int i = 0; i < numServices; i++) {
        ReadService readService = new ReadService();
        readService.setOnSucceeded(e -> servicesPending.set(servicesPending.get() - 1));
        readService.start();
    }
    
}

另一方面,如果您在服务完成时所做的工作与UI无关,那么您可以创建一个新的线程,该线程将阻止服务完成,然后在该后台线程上执行该工作。实现这一点的一种方法是使用CountDownLatch

@Override
public void start(Stage stage) {

    int numServices = 3 ;

    CountDownLatch latch = new CountDownLatch(numServices);

    for (int i = 0; i < numServices; i++) {
        ReadService readService = new ReadService();
        readService.setOnSucceeded(e -> latch.countDown());
        readService.start();
    }

    Thread onServicesCompleted = new Thread(() -> {
        try {
            latch.await();
        } catch(InterruptedException exc) {
            Thread.currentThread().interrupt();
        }
        System.out.println("Services done");
        // other work to do when services are complete...
    });
    onServicesCompleted.start();
    
}

@jewelsea在评论中提出了类似的解决方案。如果使用Tasks而不是Services,则可以调用get(),该函数将一直阻塞,直到任务完成:

@Override
public void start(Stage stage) {

    int numServices = 3 ;

    List<Task<Boolean>> tasks = new ArrayList<>();
    ExecutorService exec = Executors.newCachedThreadPool();


    for (int i = 0; i < numServices; i++) {
        ReadService readService = new ReadService();
        tasks.add(readService);
    }

    exec.invokeAll(tasks);

    Task<Void> onServicesCompleted = new Task<>() {
        @Override
        protected Void call() throws Exception {
            for (Task<Boolean> task : tasks) {
                task.get();
            }
            System.out.println("Services Done");
            // other work to be done...
        }
    };
    exec.execute(onServicesCompleted);

}

class ReadService extends Task<Boolean> {
    @Override
    protected synchronized Boolean call() throws Exception {
        // do something, for example read a file
        System.out.println("wait...");
        wait(5000);
        System.out.println("waiting done");
        return null;
    }
}

如果您想在单个ReadService都完成时执行更多后台工作,然后希望在此之后执行UI工作,则此解决方案非常好(只需使用onServicesCompleted.setOn成功(...))。

 类似资料:
  • 问题内容: 有什么方法可以简单地等待所有线程处理完成?例如,假设我有: 如何更改此方法,以便该方法在注释处暂停直到所有线程的方法退出?谢谢! 问题答案: 你将所有线程放入数组中,全部启动,然后进行循环 每个连接将阻塞,直到相应的线程完成为止。线程的完成顺序可能不同于你加入线程的顺序,但这不是问题:退出循环时,所有线程均已完成。

  • 问题内容: 我通过将操作拆分为可用的确切内核数来并行化操作,然后通过启动相同数量的AsyncTask,对数据的不同部分执行相同的操作。 我正在使用以并行化它们的执行。 我想知道每个线程何时完成其工作,以便结合所有结果并执行进一步的操作。 我能怎么做? 问题答案: 您还可以简单地将共享库中的计数器递减作为的一部分。由于在同一线程(主线程)上运行,因此您不必担心同步。 更新1 共享对象可能看起来像这样

  • 我正在编写一个应用程序,用谷歌的凌空API执行一系列请求。问题是我不知道请求什么时候完成。在我进一步行动之前,我需要知道一个请求是否已经完成。我不能用while循环或sleep/wait方法等待一定时间,因为它似乎会停止执行请求的线程。显然,请求有onResponse回调,我可以用它来标记单个请求何时完成。但我有一个活动可以发出多个请求,我希望该活动处于待机状态,直到所有请求都得到处理。就像我说的

  • 有时我看到一些线程还没有完成他们的工作,服务杀死那个线程,我怎么能强迫服务等待,直到线程完成他们的工作? 这是我的代码: 我看到了一些例外。future.is完成())块。我怎么能确保每一个未来是当执行者服务关闭?

  • 问题内容: 我有一个循环,可以调用API并将结果编译成数组。我如何等待所有调用完成后才能恢复执行?我看到了一系列有关如何等到打完一个电话的答案,但我不知道如何检查所有这些。如果我做一个while循环,一直等到’obj’是正确的长度,则页面只会停顿直到调用完成,这不是我想要的。请帮助? 问题答案: 如果您使用jQuery的deferred,这很容易。有一种方法,等待多个诺言完成,然后运行回调。那就是

  • 问题内容: 我的问题: 如何在a上执行一堆线程对象并等待它们全部完成后再继续? 我是ThreadPoolExecutor的新手。因此,此代码是测试以了解其工作方式。现在我什至都不用对象填充,因为我不理解如何在不调用另一个队列的情况下开始队列。无论如何,现在我只是打电话给我,但我认为我仍然缺少一些东西。任何提示都很棒!谢谢。 RunnableObject类: 问题答案: 你应该循环