Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/jsf/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 在SupplySync阻止主线程后使用Accept_Multithreading_Java 8_Block_Completable Future - Fatal编程技术网

Multithreading 在SupplySync阻止主线程后使用Accept

Multithreading 在SupplySync阻止主线程后使用Accept,multithreading,java-8,block,completable-future,Multithreading,Java 8,Block,Completable Future,我正在开发一个与其他web应用程序通信的web应用程序。我的系统不时地向其他系统发送HTTP请求作为通知。因为它们的响应对我来说不是必需的,所以我使用Java 8 CompletableFuture SupplySync发送请求,并使用Accept打印它们的响应,这样我的主线程就不会被阻塞。然而,我发现CompletableFuture函数链每次大约需要100到200毫秒,这让我感到困惑,因为据我所知,Accept()应该与SupplySync()在同一个线程中运行 我用下面的代码模拟了我的过程

我正在开发一个与其他web应用程序通信的web应用程序。我的系统不时地向其他系统发送HTTP请求作为通知。因为它们的响应对我来说不是必需的,所以我使用Java 8 CompletableFuture SupplySync发送请求,并使用Accept打印它们的响应,这样我的主线程就不会被阻塞。然而,我发现CompletableFuture函数链每次大约需要100到200毫秒,这让我感到困惑,因为据我所知,Accept()应该与SupplySync()在同一个线程中运行

我用下面的代码模拟了我的过程

public static void run() {
    long start = System.currentTimeMillis();
    log.info("run start -> " + new Timestamp(start));
    CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 42;
    }).thenAccept(res -> log.info("run result -> " + res + ", time -> " + new Timestamp(System.currentTimeMillis())));
    log.info("run duration ->" + (System.currentTimeMillis() - start));
}

public static void runAsync() {
    long start = System.currentTimeMillis();
    log.info("runAsync start -> " + new Timestamp(start));
    CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return 42;
    }).thenAcceptAsync(res -> log.info("runAsync result -> " + res + ", time ->" + new Timestamp(System.currentTimeMillis())));
    log.info("runAsync duration ->" + (System.currentTimeMillis() - start));
}

public static void main(String[] args) throws InterruptedException {
    Test.run();
    Test.runAsync();
    Thread.sleep(1000);
}
run()方法使用带有SupplySync()的thenAccept(),而runAsync()使用ThenAcceptySync()。我希望这两个过程都只需要几毫秒。然而,实际产出是:

10:04:54.632 [main] INFO Test - run start -> 2017-12-08 10:04:54.622
10:04:54.824 [main] INFO Test - run duration ->202
10:04:54.824 [main] INFO Test - runAsync start -> 2017-12-08 10:04:54.824
10:04:54.826 [main] INFO Test - runAsync duration ->2
10:04:55.333 [ForkJoinPool.commonPool-worker-1] INFO Test - run result -> 42, time -> 2017-12-08 10:04:55.333
10:04:55.333 [ForkJoinPool.commonPool-worker-3] INFO Test - runAsync result -> 42, time ->2017-12-08 10:04:55.333
我们可以看到run()需要202毫秒,这是runAsync()持续时间的100倍,runAsync()只需要2毫秒

我不明白202毫秒的开销是从哪里来的,显然不是supplaysnc()中的lambda函数休眠500毫秒

有人能解释一下为什么run()方法会阻塞吗?我是否应该始终使用acceptsync()而不是accept()


非常感谢。

200毫秒是线程池和所有支持它的类的启动时间

如果您交换主类中的语句,这一点就会变得很明显:

public static void main(String[] args) throws InterruptedException {
    Test.runAsync();
    Test.run();
    Thread.sleep(1000);
}
现在
Test.runAsync()
是需要200毫秒和
Test.run()的调用在2毫秒内完成

…因为据我所知,Accept()应该与SupplySync()在同一线程中运行

你的理解是错误的

发件人:

  • 为非异步方法的依赖完成提供的操作可以由完成当前CompletableFuture的线程执行,也可以由完成方法的任何其他调用方执行
最明显的结果是,当未来已经完成时,传递给
然后accept()
的函数将直接在调用方的线程中计算,因为未来不可能命令完成它的线程。事实上,
CompletableFuture
与线程根本没有关联,因为任何人都可以对其调用
complete
,而不仅仅是执行传递给
supplyAsync
供应商的
线程。这也是
cancel
不支持中断的原因。未来不知道哪些线程可能尝试完成它

不太明显的后果是,即使是上述行为也无法得到保证。短语“或由完成方法的任何其他调用方”并不将其限制为注册依赖操作的完成方法的调用方。它也可以是在同一将来注册从属操作的任何其他调用方。因此,如果两个线程在同一个将来同时调用
然后应用
,那么它们中的任何一个都可能最终对两个函数进行求值,甚至更奇怪的是,每个线程都可能最终执行另一个线程的操作。本规范并不排除这一点

对于您在问题中提供的测试用例,您更有可能测量初始开销,如中所述。但是,对于web应用程序中框架只初始化一次的实际问题,您很可能会在错误理解
然后应用
的行为(或者通常的任何非异步链接方法)上绊倒。如果要确保求值不会发生在调用方的线程中,则必须使用
然后使用applyasync