【问题标题】:Asynchronous CompletableFuture returning synchronously to single thread ExecutorService异步 CompletableFuture 同步返回到单线程 ExecutorService
【发布时间】:2017-09-22 01:13:25
【问题描述】:

我正在创建一个单线程 ExecutorService,并将需要异步执行的任务 (CompletableFuture) 分配给该单线程服务(同时尝试了 runAsync 和 supplyAsync)。

package Executor;

import java.util.Date;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorResolver {

    ExecutorService es = Executors.newSingleThreadExecutor();
    volatile int counter = 2;
    static int ten = 10;
    static int five = 5;

    public void printer() {

        System.out.println("This thread is complete :" + Thread.currentThread().getName());
        System.out.println(new Date(System.currentTimeMillis()));

    }

    public void execute() {

        CompletableFuture<Void> ct = CompletableFuture.allOf(CompletableFuture.runAsync(() -> {
            try {
                Thread t = new Thread();
                Thread.sleep(ten * 1000);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, es).thenRunAsync(this::printer), CompletableFuture.runAsync(() -> {
            try {
                Thread t = new Thread();
                Thread.sleep(five * 1000);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, es).thenRunAsync(this::printer)

        );

    }

    public static void main(String args[]) {

        ExecutorResolver er = new ExecutorResolver();

        er.execute();

        for (int i = 0; i < 1000; i++) {
            System.out.println("Current thread name : " + Thread.currentThread().getName() + i);
        }
        System.out.println(new Date(System.currentTimeMillis()));

    }

}

但是它们是同步执行的,

See the console log which waits for thread that sleeps for 10 secs and then the executes the one which sleeps for 5 seconds

请让我知道这是可能的还是我做错了什么?

【问题讨论】:

  • 如果你只有一个线程,你想如何并行运行两段不同的代码?
  • 这些Thread t = new Thread(); 行无效。新构建的线程没有要执行的相关操作,并且无论如何都不会启动。您对这些线路有何期待?
  • @SpiderPig :我不希望它们并行运行,将它们视为 Web 服务调用,只是希望这两个活动的返回时间不同,比如第一个启动的活动,有 10秒睡眠,应在第二秒后返回,睡眠 5 秒。
  • @Holger:先生,可能是它们没有效果,可能是我遗漏了某些部分,我只想
  • 首先,正如已经说过的,在某处写Thread t = new Thread();根本没有任何效果。其次,你的“异步”作业由指定的executor执行,这就是executor的含义,顾名思义。没有“唤醒执行者服务”这样的事情。由于执行器是单线程的,因此作业是单线程执行的,一个接一个。第三,不,完整的未来无法通过调用sleep 神奇地发现您正在浪费线程。你有一个线程,你让那个线程休眠。一个正在睡觉的线程在睡觉,没有别的。

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


【解决方案1】:

我相信您正在尝试做的是使用单线程异步编程风格。这种风格在 Javascript 尤其是 node.js 应用程序中被大量使用,因为它非常适合必须同时处理许多客户端的服务器端代码,这在 node.js 的创建者this talk 中得到了很好的解释。然而,在 Java 世界中,由于某种原因,这种编程风格并不是很普遍。所以也许你想先学习 node.js 编程。之后,您可以将在那里学到的东西翻译成 Java。 无论如何,我改变了你的代码,我认为它现在正在做你想要的。问题是您不能通过阻塞线程来执行延迟。相反,您也必须为此使用 Future。

package executor;

import java.util.Date;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.Timer;
import java.util.TimerTask;

public class ExecutorResolver {
    private final ExecutorService es = Executors.newSingleThreadExecutor();
    private static final Timer timer = new Timer();

    public static CompletableFuture<Void> delay(long delay) {
      CompletableFuture<Void> fut = new CompletableFuture<>();
      timer.schedule(new TimerTask() {
        @Override
        public void run() {
          fut.complete(null);
        }
      }, delay);
      return fut;
    }

    public static Date date() {
      return new Date(System.currentTimeMillis());
    }

    public void execute() {
        CompletableFuture<Void> ct = CompletableFuture.allOf(
            CompletableFuture
                .runAsync(() -> {
                    System.out.println(date() + ": started first async operation in thread " + Thread.currentThread());
                }, es)
                .thenComposeAsync(x -> delay(10000), es)
                .thenRunAsync(() -> {
                  System.out.println(date() + ": completed first async operation in thread " + Thread.currentThread());
                }, es)
            ,

            CompletableFuture
                .runAsync(() -> {
                    System.out.println(date() + ": started second async operation in thread " + Thread.currentThread());
                }, es)
                .thenComposeAsync(x -> delay(5000), es)
                .thenRunAsync(() -> {
                  System.out.println(date() + ": completed second async operation in thread " + Thread.currentThread());
                }, es)
          );
    }

    public static void main(String args[]) {
        ExecutorResolver er = new ExecutorResolver();
        er.execute();
    }
}

【讨论】:

  • 我确实在尝试这样做,我曾使用 node.js 并试图在同一个(你可以称之为事件循环)单线程中实现回调功能。谢谢你的回答。
  • 顺便说一句。你不需要CompletableFuture&lt;Void&gt; ct = CompletableFuture.allOf(这一行。只有在两个期货都完成后您想做某事时才需要它。
  • 那么我怎样才能创建一个管道(或者我怎样才能简单地为我的 ES 分配一个监听器,让我知道哪个 completableFuture 已经返回)?同样在这种情况下,我们故意创建一个异步场景。在现实世界中,是什么因素让 ES 决定方法无响应,例如:NIO 读取的大文件?最重要的是需要很长时间才能响应的网络服务?
  • 管道是什么意思?你这里已经有管道了,不是吗?或者在这个代码示例中实际上是两个管道。要检测无响应,可以使用 orTimeout 方法,但它仅在 Java 9 中引入。
猜你喜欢
  • 2017-09-14
  • 1970-01-01
  • 1970-01-01
  • 2015-11-05
  • 2019-06-30
  • 2015-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多