当 CompleteableFuture 既没有完成、取消也没有异常时会发生什么?
What happens to CompleteableFuture when it gets neither completed, cancelled nor an exception?
...与使用回调相比?
第一个例子,带回调
public class NewClass {
public static final ScheduledExecutorService SCHEDULED_EXECUTOR = Executors.newScheduledThreadPool(1);
@FunctionalInterface
public interface F_CallbackDef {
void callback(String s);
}
public void a() {
b((String s) -> {
System.out.println(s);
});
}
public void b(F_CallbackDef callback) {
SCHEDULED_EXECUTOR.schedule(() -> {
String s = "string";
Random random = new Random();
boolean cond = random.nextBoolean();
if (cond) {
boolean cond2 = random.nextBoolean();
if (cond2) {
// assume possible uncatched exeption
}
callback.callback(s);
// in every case:
// callback just moves out of scope - no problem
}
}, 1, TimeUnit.HOURS);
}
}
第二个例子,CompletableFuture
public class NewClass1 {
public static final ScheduledExecutorService SCHEDULED_EXECUTOR = Executors.newScheduledThreadPool(1);
public void a() {
CompletableFuture<String> cf = b();
cf.thenAcceptAsync((String s) -> {
System.out.println(s);
});
// cf moves out of scope immediatly
// but also it gets never completed, nor cancelled
}
CompletableFuture<String> b() {
CompletableFuture<String> result = new CompletableFuture<>();
SCHEDULED_EXECUTOR.schedule(() -> {
String s = "string";
Random random = new Random();
boolean cond = random.nextBoolean();
if (cond) {
boolean cond2 = random.nextBoolean();
if (cond2) {
// assume possible uncatched exception
}
result.complete(s);
}
// assume cond = false or cond2 = false
// this is not about that result.cancel() SHOULD be called, it is a bug if you will
}, 1, TimeUnit.HOURS);
return result;
}
}
问题是:
- 示例 2 中的 cf 发生了什么/(何时)它会被垃圾收集删除?
- 是否有更好的方法将示例 1 "translate" 转换为示例 2?
在您的回答中,请对技术论点保持敏锐,而不是 preferred/improvable 代码(因为这不是这个问题的目的),也不是 cf.cancel 没有得到打电话。
在示例 1 中,当您调用 a
时,它会调用 b
来安排任务,并调用 a
returns。在某些时候,回调将由 运行 在 b
.
中创建的任务线程执行
在示例 2 中,当您调用 a
时,它会调用安排任务的 b
和 a
returns。 thenAcceptAsync
中的代码永远不会执行,因为您从未调用过 Future 的 get
。 cf
是局部变量,因此它指向的对象在 a
终止后可用于 GC。在某些时候 GC 可能会删除它。
如果您要在代码中的某处调用 get
,它将阻塞直到任务完成,然后在调用线程的上下文中执行 thenAcceptAsync
中的子句get
.
无法从示例 1 到示例 2 translate
,因为它们在做 2 件完全不同的事情,根据您的要求,每件事情都可能是正确的。
您似乎对另一件事感到困惑:期货既未完成也未取消,它们指向的任务是 ARE。他们只提供在未来获得他们指向的任务结果的能力。
CompletableFuture
会怎样?什么时候会被垃圾收集删除?
在您的代码中,您有 3 个对 CompletableFuture
:
的引用
a()
中的局部变量cf
b()
中的局部变量result
- lambda 中捕获的引用传递给
SCHEDULED_EXECUTOR.schedule()
另请注意,至少只要可完成的未来未完成,传递给 thenAcceptAsync()
的 lambda 就需要保留,除非可完成的未来本身是 gc'd。因此,即使您不保留对它的引用,此 lambda 也可能比方法的执行时间更长。
关于 CompletableFuture
s 没有什么特别适用的,标准 GC 规则适用:当没有人再引用它时,它将有资格进行垃圾收集 - 或者更准确地说,当不再存在到 GC 根的路径时。
对于局部变量,很容易看出它们何时停止引用它。对于捕获的引用,不幸的是,只要 lambda 存在,它就会一直存在(即使它不再使用它)。假设优化,当没有更多的执行计划时,lambda 将符合 GC 的条件——所以这里就是当您关闭执行程序时。
一旦这些引用消失,它将有资格进行 GC。
是否有更好的方法将示例 1 "translate" 转换为示例 2?
翻译实际上并不正确,因为CompletableFuture
只能完成一次。在示例 1 中,每次成功执行都会调用您的回调,但在示例 2 中,只有第一个成功的执行才会触发它。对 result.complete(s)
的下一次调用实际上将被忽略。
CompletableFuture
不是为处理结果值流而设计的。为此,您应该使用可观察对象和订阅者进行反应式编程。
如果这是针对单次执行的,则转换是正确的,但是最好只依赖 CompletableFuture.supplyAsync()
而不是自己处理未来。这也将自动提供异常处理功能。
...与使用回调相比?
第一个例子,带回调
public class NewClass {
public static final ScheduledExecutorService SCHEDULED_EXECUTOR = Executors.newScheduledThreadPool(1);
@FunctionalInterface
public interface F_CallbackDef {
void callback(String s);
}
public void a() {
b((String s) -> {
System.out.println(s);
});
}
public void b(F_CallbackDef callback) {
SCHEDULED_EXECUTOR.schedule(() -> {
String s = "string";
Random random = new Random();
boolean cond = random.nextBoolean();
if (cond) {
boolean cond2 = random.nextBoolean();
if (cond2) {
// assume possible uncatched exeption
}
callback.callback(s);
// in every case:
// callback just moves out of scope - no problem
}
}, 1, TimeUnit.HOURS);
}
}
第二个例子,CompletableFuture
public class NewClass1 {
public static final ScheduledExecutorService SCHEDULED_EXECUTOR = Executors.newScheduledThreadPool(1);
public void a() {
CompletableFuture<String> cf = b();
cf.thenAcceptAsync((String s) -> {
System.out.println(s);
});
// cf moves out of scope immediatly
// but also it gets never completed, nor cancelled
}
CompletableFuture<String> b() {
CompletableFuture<String> result = new CompletableFuture<>();
SCHEDULED_EXECUTOR.schedule(() -> {
String s = "string";
Random random = new Random();
boolean cond = random.nextBoolean();
if (cond) {
boolean cond2 = random.nextBoolean();
if (cond2) {
// assume possible uncatched exception
}
result.complete(s);
}
// assume cond = false or cond2 = false
// this is not about that result.cancel() SHOULD be called, it is a bug if you will
}, 1, TimeUnit.HOURS);
return result;
}
}
问题是:
- 示例 2 中的 cf 发生了什么/(何时)它会被垃圾收集删除?
- 是否有更好的方法将示例 1 "translate" 转换为示例 2?
在您的回答中,请对技术论点保持敏锐,而不是 preferred/improvable 代码(因为这不是这个问题的目的),也不是 cf.cancel 没有得到打电话。
在示例 1 中,当您调用 a
时,它会调用 b
来安排任务,并调用 a
returns。在某些时候,回调将由 运行 在 b
.
在示例 2 中,当您调用 a
时,它会调用安排任务的 b
和 a
returns。 thenAcceptAsync
中的代码永远不会执行,因为您从未调用过 Future 的 get
。 cf
是局部变量,因此它指向的对象在 a
终止后可用于 GC。在某些时候 GC 可能会删除它。
如果您要在代码中的某处调用 get
,它将阻塞直到任务完成,然后在调用线程的上下文中执行 thenAcceptAsync
中的子句get
.
无法从示例 1 到示例 2 translate
,因为它们在做 2 件完全不同的事情,根据您的要求,每件事情都可能是正确的。
您似乎对另一件事感到困惑:期货既未完成也未取消,它们指向的任务是 ARE。他们只提供在未来获得他们指向的任务结果的能力。
CompletableFuture
会怎样?什么时候会被垃圾收集删除?
在您的代码中,您有 3 个对 CompletableFuture
:
a()
中的局部变量b()
中的局部变量- lambda 中捕获的引用传递给
SCHEDULED_EXECUTOR.schedule()
cf
result
另请注意,至少只要可完成的未来未完成,传递给 thenAcceptAsync()
的 lambda 就需要保留,除非可完成的未来本身是 gc'd。因此,即使您不保留对它的引用,此 lambda 也可能比方法的执行时间更长。
关于 CompletableFuture
s 没有什么特别适用的,标准 GC 规则适用:当没有人再引用它时,它将有资格进行垃圾收集 - 或者更准确地说,当不再存在到 GC 根的路径时。
对于局部变量,很容易看出它们何时停止引用它。对于捕获的引用,不幸的是,只要 lambda 存在,它就会一直存在(即使它不再使用它)。假设优化,当没有更多的执行计划时,lambda 将符合 GC 的条件——所以这里就是当您关闭执行程序时。
一旦这些引用消失,它将有资格进行 GC。
是否有更好的方法将示例 1 "translate" 转换为示例 2?
翻译实际上并不正确,因为CompletableFuture
只能完成一次。在示例 1 中,每次成功执行都会调用您的回调,但在示例 2 中,只有第一个成功的执行才会触发它。对 result.complete(s)
的下一次调用实际上将被忽略。
CompletableFuture
不是为处理结果值流而设计的。为此,您应该使用可观察对象和订阅者进行反应式编程。
如果这是针对单次执行的,则转换是正确的,但是最好只依赖 CompletableFuture.supplyAsync()
而不是自己处理未来。这也将自动提供异常处理功能。