Search code examples
javaconcurrencycompletable-future

Passing Class that runs task to Completable Future SupplyAsync


Trying to compare implementations of futures vs completed futures and check if the non blocking nature of completable futures is a better use case for my problem. Having an issue getting my completable impl to work correctly.

        Collection<Future<ArrayList<MeterTariffValues>>> futures = new ArrayList<>();

        List<CompletableFuture<GetSiteMeterTariffValues>> completableFutures = new ArrayList<>(); 


        for (Site site : sites) {
            completableFutures.add(
                CompletableFuture.supplyAsync(new Supplier<GetSiteMeterTariffValues>() {
                    @Override
                    public GetSiteMeterTariffValues get() {
                        return  new GetSiteMeterTariffValues(
                            site.getSite_id(),
                            methaneConversionVal,
                            nitrogenConversionVal,
                            bu_id,
                            region_id,
                            facility_id,
                            status,
                            resource_id,
                            metertype_id,
                            currentCalendarYear,
                            currentFiscalYear,
                            fiscalYearStartMonth,
                            dates,
                            meterMapper,
                            sqlSessionTemplate);
                    }
                }, taskExecutor)
            );
            
            futures.add(
                    taskExecutor.submit(
                            new GetSiteMeterTariffValues(
                                    site.getSite_id(),
                                    methaneConversionVal,
                                    nitrogenConversionVal,
                                    bu_id,
                                    region_id,
                                    facility_id,
                                    status,
                                    resource_id,
                                    metertype_id,
                                    currentCalendarYear,
                                    currentFiscalYear,
                                    fiscalYearStartMonth,
                                    dates,
                                    meterMapper,
                                    sqlSessionTemplate)));
        }

The issue with the Completable implementation, is that it wont recognize that GetSiteMeterTariffValues returns a different type after the task is complete.

It returns

public ArrayList<MeterTariffValues> call() 

But task executor is fine with this

        for (Future<ArrayList<MeterTariffValues>> future : futures) {

            long start = System.currentTimeMillis();
            ArrayList<MeterTariffValues> siteMeterTariffMonthlyValues = future.get();
            long end = System.currentTimeMillis();
            long totalMS = end - start;
            total += totalMS;
            meterTariffValues.addAll(siteMeterTariffMonthlyValues);
        }

So im wondering how i can do similar the above with completablefutures.

Note:GetSiteMeterTariffValues implements Callable<ArrayList>


Solution

  • CompletableFuture.supplyAsync() expects a Supplier which is the equivalent of Callable for ExecutorService.

    The way you do it currently, you are just providing a Supplier that creates a Callable, but of course your Callable (GetSiteMeterTariffValues) is not called.

    You just need to make GetSiteMeterTariffValues implement Supplier and use it directly in CompletableFuture.supplyAsync():

    CompletableFuture.supplyAsync(
        new GetSiteMeterTariffValues(
            site.getSite_id(),
            methaneConversionVal,
            nitrogenConversionVal,
            bu_id,
            region_id,
            facility_id,
            status,
            resource_id,
            metertype_id,
            currentCalendarYear,
            currentFiscalYear,
            fiscalYearStartMonth,
            dates,
            meterMapper,
            sqlSessionTemplate),
        taskExecutor)
    

    Note that Supplier does not allow throwing checked exceptions, so you cannot just use a method reference to Callable.call().