我在研究未来的时候有个问题。这个 get()
/ join()
方法正在阻止调用。如果我不打电话给他们呢?
此代码调用 get()
:
// Case 1 - Use get()
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1_000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Hello");
}).get();
System.out.println("World!");
Thread.sleep(5_000L); // Don't finish the main thread
输出:
Hello
World!
此代码既不调用 get()
也不是 join()
:
// Case 2 - Don't use get()
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1_000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Hello");
});
System.out.println("World!");
Thread.sleep(5_000L); // For don't finish main thread
输出:
World!
Hello
我不知道为什么案例2的可运行模块起作用了。
3条答案
按热度按时间6qftjkof1#
关于
CompletableFuture
它们是立即被安排启动的(尽管您不能可靠地判断它们将在哪个线程中执行),并且在您到达的时候get
或者join
,结果可能已经就绪,即CompletableFuture
可能已经完成。在内部,一旦管道中的某个阶段准备就绪CompletableFuture
将设置为“已完成”。例如:与以下内容相同:
但当你真正开始
join
,cf3
可能已经结束了。get
以及join
只需在所有阶段完成之前阻塞,它不会触发计算;立即安排计算。一个小的补充是你可以完成一个
CompletableFuture
不必等待管道的执行完成:就像complete
,completeExceptionally
,obtrudeValue
(即使它已经完成了,这个也会设置它),等等。下面是一个有趣的例子:这将输出:
因此,即使工作开始,最终的价值是
b
,不是a
.2q5ifsrm2#
第二种情况是“工作”的,因为您使主线程睡眠的时间足够长(5秒)。工作是在引号之间,因为它不是真正的工作,只是完成。我在这里假设代码应该输出
Hello World!
才能被视为“正常工作”。在这两种情况下,请在主线程结束时尝试使用相同的代码:
Thread.sleep(100);
1.第一个线程的行为方式相同,因为get操作阻塞了主线程。事实上,对于第一种情况,你甚至不需要最后的睡眠时间。输出:
Hello World!
2.第二种情况不会输出Hello
,因为没有人告诉主线:“嘿,等这个结束”。那是什么get()
does:阻止调用者以等待任务完成。如果没有它,并且在最后设置一个较低的睡眠时间,就会调用runnable,但是无法在主线程停止之前完成它的工作。输出:
World!
这也是为什么在第一种情况下Hello World!
(首先是runnable的输出,然后是main的输出-这意味着主线程被阻塞,直到get()
返回),而第二个显示了阅读障碍的微妙迹象:World Hello!
但它不是诵读困难,它只是执行它被告知的。在第二种情况下,会发生这种情况:1.runnable被称为。
2.主线程继续它的进程,打印(“world!)
3.
Sleep
设置时间:runnable上1秒/main上5秒(runnable的睡眠也可以在第二步执行,但我把它放在这里是为了澄清行为)4.runnable任务在1秒后打印(“hello”),completablefuture完成。
5.5秒后,主线程停止。
所以你的runnable可以打印出来
Hello
因为它能够在这5秒超时之间执行命令。例如,如果将最后5秒的超时时间减少到0.5秒,则
qv7cva1a3#
我不知道为什么
Runnable
第二组正在工作。没有理由不起作用。
这个
runAsync(...)
方法表示异步执行任务。假设应用程序没有过早结束,不管您是否等待任务完成,任务最终都会完成。这个
CompletableFuture
提供各种等待任务完成的方法。但在你的例子中,你并不是为了这个目的而使用它。取而代之的是Thread.sleep(...)
调用你的主方法也有同样的效果;i、 等待的时间足够长,任务(可能)已经完成了。所以呢"Hello"
之前是否有输出"World"
.重申一下
get()
调用不会导致任务发生。而是等待它发生。使用
sleep
等待事件(如任务完成)发生是个坏主意:睡眠不能判断事件是否发生!
你通常不知道这件事要花多长时间才能发生,你也不知道要睡多久。
如果你睡得太久,你就有“死时间”(见下文)。
如果你睡眠时间不够长,事件可能还没有发生。所以你需要一次又一次的测试和睡眠。。。
即使在这个例子中,理论上也有可能
sleep
主要是在sleep
在任务中。基本上
CompletableFuture
是提供一种等待任务完成并交付结果的有效方法。你应该用它。。。举例说明。您的应用程序在输出之间等待(并浪费)约4秒
"Hello"
以及"World!"
. 如果你用了CompletableFuture
因为它的目的是使用,你不会有这4秒的“死区时间”。1-例如,某些外部代理可能能够有选择地“暂停”正在运行任务的线程。可以通过设置断点来完成。。。