从未来获得结果而不完成所有

时间:2018-05-26 14:59:47

标签: java multithreading future

我正在创建10个线程并向其添加2种作业,如下所示。

public class ParallelAdder {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            ExecutorService executor = Executors.newFixedThreadPool(10);
            List<Future<Integer>> list = new ArrayList<Future<Integer>>();
            for (int i = 0; i < 10; i++) {
                Future<Integer> future;
                if (i % 2 == 0) {
                    future = executor.submit(new Call1());
                } else {
                    future = executor.submit(new Call2());
                }

                list.add(future);

            }

            for(Future<Integer> fut : list) {
                System.out.println("From future is "+fut.get());
            }
        }
    }

class Call1 implements Callable<Integer> {
    public Integer call() throws Exception {
        System.out.println("Calling 1");
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 10;
    }

}

class Call2 implements Callable<Integer> {
    public Integer call() throws Exception {
        System.out.println("Calling 2");
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 20;
    }

}

与Call1相比,Call2作业返回的速度更快。 在我将来的列表中,我希望工作完成后立即获得结果。它不应该取决于所有其他工作要做 这里Call2返回等待Call1。怎么解决这个问题?

1 个答案:

答案 0 :(得分:1)

问题在于您通过在此处调用阻止get来等待:

for(Future<Integer> fut : list) {
    System.out.println("From future is "+fut.get());
}

要解决此问题,您需要使用反应式代码。您可以使用可完成的未来API,该API专为声明性反应式Future-like API而设计:

ExecutorService executor = Executors.newFixedThreadPool(10);

Supplier<Integer> call1Supplier = () -> {
    System.out.println("Calling 1");
    try {
        Thread.sleep(100000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return 10;
};

Supplier<Integer> call2Supplier = () -> {
    System.out.println("Calling 1");
    try {
        Thread.sleep(10);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return 10;
};

然后可以将其提交给同一个执行程序服务,但使用支持类似回调对象的被动CompletableFuture

List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) {
        CompletableFuture<Void> future = 
                CompletableFuture.supplyAsync(call1Supplier, executor)
                .thenAccept(number -> System.out.println("From future is " + number));
        futures.add(future);
    } else {
        CompletableFuture<Void> future = 
                CompletableFuture.supplyAsync(call2Supplier, executor)
                .thenAccept(number -> System.out.println("From future is " + number));
        futures.add(future);
    }
}

以下只是为了确保在所有异步任务完成之前当前线程不会退出。但如果它是一个长期运行的应用程序,例如服务器,这可能是不必要的

for (CompletableFuture<Void> future : futures) {
    future.join();
}

请注意,我列出了Call1Call2的代码,因为Callable实施并非必要。但是将它保存在一个单独的类中仍然是个好主意(除非函数对象正常)。