我正在运行这样的多个服务:(例如,在多个线程中读取文件)
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;
}
};
}
}
您正在从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在评论中提出了类似的解决方案。如果使用Task
s而不是Service
s,则可以调用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 共享对象可能看起来像这样
有时我看到一些线程还没有完成他们的工作,服务杀死那个线程,我怎么能强迫服务等待,直到线程完成他们的工作? 这是我的代码: 我看到了一些例外。future.is完成())块。我怎么能确保每一个未来是当执行者服务关闭?
我正在编写一个应用程序,用谷歌的凌空API执行一系列请求。问题是我不知道请求什么时候完成。在我进一步行动之前,我需要知道一个请求是否已经完成。我不能用while循环或sleep/wait方法等待一定时间,因为它似乎会停止执行请求的线程。显然,请求有onResponse回调,我可以用它来标记单个请求何时完成。但我有一个活动可以发出多个请求,我希望该活动处于待机状态,直到所有请求都得到处理。就像我说的
问题内容: 我有一个循环,可以调用API并将结果编译成数组。我如何等待所有调用完成后才能恢复执行?我看到了一系列有关如何等到打完一个电话的答案,但我不知道如何检查所有这些。如果我做一个while循环,一直等到’obj’是正确的长度,则页面只会停顿直到调用完成,这不是我想要的。请帮助? 问题答案: 如果您使用jQuery的deferred,这很容易。有一种方法,等待多个诺言完成,然后运行回调。那就是
问题内容: 我的问题: 如何在a上执行一堆线程对象并等待它们全部完成后再继续? 我是ThreadPoolExecutor的新手。因此,此代码是测试以了解其工作方式。现在我什至都不用对象填充,因为我不理解如何在不调用另一个队列的情况下开始队列。无论如何,现在我只是打电话给我,但我认为我仍然缺少一些东西。任何提示都很棒!谢谢。 RunnableObject类: 问题答案: 你应该循环