【问题标题】:Java's CompletableFuture and ThreadsJava 的 CompletableFuture 和线程
【发布时间】:2018-06-18 10:53:03
【问题描述】:

我想用CompletableFuture Java 8-9 启动线程,使用异步模式,这些是我的类和我的线程:

我有 3 个线程。我的课程包含一个方法myMethod()

Class_1 class_1 = new Class_1();

Class_2 class_2 = new Class_2(); 

Class_3 class_3 = new Class_3();

如下设置我的Runnables:

Runnable runnableClass_1 = new Runnable(){
    public void run(){
        class_1.myMethod();
        try { Thread.sleep(0); } catch (InterruptedException e) { e.printStackTrace(); }
    }
};

Runnable runnableClass_2 = new Runnable(){
    public void run(){
        class_2.myMethod();
        try { Thread.sleep(0); } catch (InterruptedException e) { e.printStackTrace(); }
    }
};

Runnable runnableClass_3 = new Runnable(){
    public void run(){
        class_3.myMethod();
        try { Thread.sleep(0); } catch (InterruptedException e) { e.printStackTrace(); }
    }
};  

创建线程:

Thread t_1 = new Thread( runnableClass_1 );

Thread t_2 = new Thread( runnableClass_2 );

Thread t_3 = new Thread( runnableClass_3 );

最后,我的问题是如何使用CompletableFuture异步模式启动这三个线程。

【问题讨论】:

  • 如果您不需要自己控制线程处理,您可以简单地使用CompletableFuture.runAsync()。如果您需要更多控制,请使用带有Executor 参数的版本并自定义您的Executor。最后,如果你真的需要使用这3个线程,你必须自己在Runnable中管理CompletableFutures。

标签: java multithreading asynchronous java-8 completable-future


【解决方案1】:

以下是实现相同的方法:

List<String> results = new ArrayList<String>();

        CompletableFuture<Void> run1 = CompletableFuture.runAsync(() -> {
                pauseSeconds(2);
                results.add("first task");
            }, service);

        CompletableFuture<Void> run2 = CompletableFuture.runAsync(() -> {
                pauseSeconds(3);
                results.add("second task");
            }, service);

        CompletableFuture<Void> finisher = run1.runAfterBothAsync(run2,
                                            () -> results.add(results.get(0)+ "&"+results.get(1)),service);
         pauseSeconds(4);
         System.out.println("finisher.isDone() = "+finisher.isDone());
         System.out.println("results.get(2) = "+results.get(2));
//       assert(finisher.isDone(), is(true));
//       assertThat(results.get(2),is("first task&second task"));
        }

public static void pauseSeconds(int num){
        try {
            Thread.sleep(num);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

【讨论】:

    【解决方案2】:

    您如何设置(并可能组合)您的未来取决于您的用例:这些未来是否相互依赖?您需要按顺序执行它们还是可以并行运行它们?你关心所有三个结果还是只需要先完成的未来?

    根据您的回答,您可以使用 flatMap/bind 组合子(它们对 CompletableFuture 有不同的名称,但您可以解决)顺序链接您的期货,或者您可以从当前线程中生成所有期货(让它们并行运行),然后等待它们全部完成。你也可以为CompletableFuture工厂方法指定一个特定的线程池,只使用默认的(ForkJoinPool)。

    所有这些都可以通过vavr 提供的Future 的一元版本非常简洁地完成。但是,如果您查看其documentation,您也可以使用CompletableFuture 提出解决方案。

    更新/请求示例

    下面的例子基本上取自Java 8 in Action github repository,其中提供的future是并行运行的,所有的结果都被累积到一个集合中。您所做的是将List&lt;Future&lt;T&gt;&gt; 转换为Future&lt;List&lt;T&gt;&gt;

        final long startTime = System.currentTimeMillis();
        final CompletableFuture<String> foo = CompletableFuture.supplyAsync(() -> {
            final long timeout = 500;
            try {
                Thread.sleep(timeout);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(String.format("foo on %s sleeping for %s", Thread.currentThread(), timeout));
            return "foo";
        });
        final CompletableFuture<String> bar = CompletableFuture.supplyAsync(() -> {
            final long timeout = 100;
            try {
                Thread.sleep(timeout);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(String.format("bar on %s sleeping for %s", Thread.currentThread(), timeout));
            return "bar";
        });
        final CompletableFuture<String> baz = CompletableFuture.supplyAsync(() -> {
            final long timeout = 1000;
            try {
                Thread.sleep(timeout);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(String.format("baz on %s sleeping for %s", Thread.currentThread(), timeout));
            return "baz";
        });
    
        CompletableFuture
                .supplyAsync(() -> Stream.of(foo, bar, baz).map(future -> future.join()).collect(Collectors.toList()))
                .thenAccept(done -> System.out.println(String.format("Done with all futures %s", done)))
                .thenRun(() -> System.out.println(String.format("Running all futures in parallel took %s millis", System.currentTimeMillis() - startTime)));
    

    输出应该是这样的:

    bar on Thread[ForkJoinPool.commonPool-worker-2,5,main] sleeping for 100
    foo on Thread[ForkJoinPool.commonPool-worker-9,5,main] sleeping for 500
    baz on Thread[ForkJoinPool.commonPool-worker-11,5,main] sleeping for 1000
    Done with all futures [foo, bar, baz]
    Running all futures in parallel took 1007 millis
    

    【讨论】:

    • 我对尽可能节省时间很感兴趣,在我使用CompletableFuture 之前,我的内存非常有限,所以我使用sequential 模式,现在我增加了我的备忘录然后是处理器,我'我对在parallel 中使用CompletebleFuture 感兴趣,请您举个例子。
    • 我接受你的回答 Rea,我已经被分配了一些修改,但你的主要方法被完美地保留了,;)
    • @YohanT 抱歉让您感到困惑。当我谈论接受我的答案时,我指的是 StackOverflow 上的“接受答案”功能。你可以在这里阅读:stackoverflow.com/tour
    猜你喜欢
    • 2021-06-04
    • 2021-02-20
    • 2018-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-23
    • 2015-04-19
    相关资源
    最近更新 更多