CompletableFuture实现,动态多线程无法正常工作

时间:2018-04-17 06:14:03

标签: java io completable-future

关于CompletableFuture功能,如果有人知道它没有动态创建多个线程。为此,我在下面的代码中尝试使用executorService但是executorService有一个固定的线程池,因此它进入阻塞状态。 您可以根据以下代码动态实现多线程中的CompletableFuture吗?

private static CompletableFuture<Integer> createCompletableFuture(ByteArrayOutputStream baOS, int totalBytes, 
            List<FileUploadMultiLocator> fileUploadList) {
        CompletableFuture<Integer> futureCount = CompletableFuture.supplyAsync(
                () -> {
                    try {
                            // simulate long running task
                            for (FileUploadMultiLocator fileUploadMultiLocator : fileUploadList) {
                                System.out.println(Thread.currentThread().getName() + " secondary task is called");
                                fileUploadMultiLocator.baOS.write(baOS.toByteArray(), 0, totalBytes);
                                fileUploadMultiLocator.setTotalBytes(totalBytes);
                                new Thread(fileUploadMultiLocator).start();
                                try {
                                    Thread.sleep(5);
                                } catch (InterruptedException e) {
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                                }
                            }
                        }
                    catch (Exception e) { }
                    return 20;
                });
        return futureCount;
    }

1 个答案:

答案 0 :(得分:0)

我认为你应该让事情更简单。我认为你应该在主线程中遍历你的列表,而不是在一个异步任务中创建N个线程,并且对于每个元素,创建一个completableFuture,给它你的&# 34; FileUploadMultiLocator&#34;可运行。每个可完成的未来都是Java公共fork-join池中的异步任务。

但是,如果要控制用于任务的线程数,可以使用CompletableFuture.runAsync(Runnable r, Executor e)。这样,您可以使用所需数量的线程准备一个线程池(使用Executors class中的静态方法,并将其用于您的工作。

请注意,您可以在java中使用其他工具。您也可以选择以下两种解决方案之一:

Java 8 Streams

如果你可以使用Java 8,你应该使用Stream power。您可以阅读更多相关信息here

总之,这些流允许您并行浏览/处理对象集合。对于您的示例,我将使用以下方法:

        // Specify the wanted number of parallel tasks, and create a thread pool accordingly.
    final int threadNb = 4;
    final ForkJoinPool pool = new ForkJoinPool(threadNb);
    // We give the entire procedure to the thread pool, which will be in charge of managing executions
    pool.submit(
        // Ask to execute each runnable in the list, in a parallel way.
        () -> fileUploadList.parallelStream().forEach(r -> r.run())
    );

    // Below block is in charge of waiting complete execution.
    pool.shutdown();
    try {
        pool.awaitTermination(1, TimeUnit.MINUTES);
    } catch (InterruptedException ex) {
        // Do whatever cancelling logic you want, or let it propagate
    }

执行人服务

但是,您不必使用流,您可以直接使用执行程序服务。为什么你应该使用这种方法而不是自己创建线程?in the following answer

        final List<Runnable> fileUploadList = null;
    // Specify the wanted number of parallel tasks.
    final int threadNb = 4;
    ExecutorService threadPool = Executors.newFixedThreadPool(threadNb);
    for (final Runnable r : fileUploadList) {
        // ... Do your pre-computing here ...
        // Now, submit asynchronous part of your task for execution
        threadPool.submit(r);
    }

    // Below block is in charge of waiting complete execution.
    threadPool.shutdown();
    try {
        threadPool.awaitTermination(1, TimeUnit.MINUTES);
    } catch (InterruptedException ex) {
        // Do whatever cancelling logic you want, or let it propagate
    }

另外,请注意,我在这里创建了一个on-shot执行器服务。但是,常见的做法是在应用程序的某个位置创建它,并使其保持活动状态,这样您就可以多次重复使用它的线程。在这种情况下,我给你的代码是错误的等待完成&#39;部分,您应该监控每个任务的未来。

最后一件事:我的例子非常简化用例。我既没有管理错误也没有按任务超时,因此在使用之前需要进行精炼。但是,我希望它有所帮助!