使用CompleteableFuture执行两个异步

时间:2018-06-14 13:35:36

标签: java asynchronous

这里是我必须快速运行的代码片段:

fillPricedServiceForLocation(location, doc, locale, services);

fillReviewsForLocation(location, doc, services);

两种方法如下:

private static void fillPricedServiceForLocation(Location location, LocationDocument doc,
    Language locale, List<Long> services) {
    if (doc.isPriceList()) {
        String locationId = doc.getLocationId();
        try {
            new PricesRepository().findServiceForLocation(locationId, services)
                .ifPresent(foundService -> {
                    String serviceId = foundService.getServiceId();
                    final LocationServices locationServices = new LocationServices();
                    locationServices.setId(Integer.valueOf(serviceId));
                    locationServices.setPrice(BigDecimal.valueOf(foundService.getPrice()));
                    locationServices.setCurrency(foundService.getCurrency());

                    ServiceName serviceName = ServiceNameProvider.getServiceName(serviceId);
                    locationServices.setName(serviceName.getName(locale));
                    location.setServices(locationServices);
                });
        } catch (Exception e) {
            log.error("Error when trying to retrieve last review for location {}", locationId,
                      e);

        }
    }
}

private static void fillReviewsForLocation(Location location, LocationDocument doc,
    List<Long> services) {
    String locationId = doc.getLocationId();
    try {
        LocationReviews locationReviews = new LocationReviews();
        locationReviews.setCount(doc.getReviewsCount());
        locationReviews.setScore(doc.getReviewsScore());

        new ReviewsRepository().findReview(locationId, services).ifPresent(
            foundReview -> locationReviews.setReview(reviewDocumentToJsonModel(foundReview)));
        location.setReviews(locationReviews);
    } catch (Exception e) {
        log.error("Error when trying to retrieve last review for location {}", locationId, e);
    }
}

他们调用两个不同的repositiories,如果他们找到了什么,他们会处理它并更新作为参数 location 传递。是否可以对这两个方法调用进行并行化,以便同时处理它们?尝试使用CompleteableFuture但无法使其运行 - 对异步编程没有多少经验。

2 个答案:

答案 0 :(得分:0)

你可以在两个不同的线程和每个线程的run()方法中编写一个函数。然后使用ExecutorService.submit(threadOne)和ExecutorService.submit(threadTwo)并行执行它。

答案 1 :(得分:0)

使用CompletableFutures,你应该能够做到:

CompletableFuture<Void> task1 = CompletableFuture.runAsync(() -> fillPricedServiceForLocation(location, doc, locale, services));

CompletableFuture<Void> task2 = CompletableFuture.runAsync(() -> fillReviewsForLocation(location, doc, services)));

task1.join();
task2.join();

这将在新的单独线程(JVM用于这些事情的默认fork-join池)中并行运行这两个任务。主线程将等待两者完成(使用join()。如果您愿意,可以在调用join()之前执行其他操作。

如果两者都在更新同一个对象(Location),请确保您的更新是线程安全的。让方法单独返回信息然后更新主线程中的公共数据结构可能更安全。这也比引入不必要的synchronized块更快。

如果您想从CompletableFuture返回一些值,可以使用supplyAsync()代替runAsync()轻松完成,这样您就可以将值返回给任务。 (它的类型不会是CompletableFuture<Void>,而是CompletableFuture<LocationReviews>CompletableFuture<LocationServices>。)

因此,例如,方法可能是这样的:

CompletableFuture<LocationServices> servicesTask = CompletableFuture.supplyAsync(() -> getPricedServiceForLocation(doc, locale, services));

CompletableFuture<LocationReviews> reviewsTask = CompletableFuture.supplyAsync(() -> getReviewsForLocation(doc, services)));

location.setServices(servicesTask.get());
location.setReviews(reviewsTask.get());

您不需要将Location作为参数传递给这些方法,它们只是异步地为您检索信息。

private static LocationServices getPricedServiceForLocation(LocationDocument doc, Language locale, List<Long> services) {
  ...
}

private static LocationReviews getReviewsForLocation(LocationDocument doc, List<Long> services) {
  ...
}