Java 在可完成的未来链中关闭外部流程
我正在寻找更好的方法来“关闭”一些资源,在Java 在可完成的未来链中关闭外部流程,java,java-8,completable-future,Java,Java 8,Completable Future,我正在寻找更好的方法来“关闭”一些资源,在CompletableFuture链中销毁外部Process。现在,我的代码大致如下所示: public CompletableFuture<ExecutionContext> createFuture() { final Process[] processHolder = new Process[1]; return CompletableFuture.supplyAsync( () -> {
CompletableFuture
链中销毁外部Process
。现在,我的代码大致如下所示:
public CompletableFuture<ExecutionContext> createFuture()
{
final Process[] processHolder = new Process[1];
return CompletableFuture.supplyAsync(
() -> {
try {
processHolder[0] = new ProcessBuilder(COMMAND)
.redirectErrorStream(true)
.start();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return PARSER.parse(processHolder[0].getInputStream());
}, SCHEDULER)
.applyToEither(createTimeoutFuture(DURATION), Function.identity())
.exceptionally(throwable -> {
processHolder[0].destroyForcibly();
if (throwable instanceof TimeoutException) {
throw new DatasourceTimeoutException(throwable);
}
Throwables.propagateIfInstanceOf(throwable, DatasourceException.class);
throw new DatasourceException(throwable);
});
}
public CompletableFuture createFuture()
{
最终流程[]流程持有者=新流程[1];
返回CompletableFuture.SupplySync(
() -> {
试一试{
processHolder[0]=新的ProcessBuilder(命令)
.redirectErrorStream(真)
.start();
}捕获(IOE异常){
抛出新的未选中异常(e);
}
返回PARSER.parse(processHolder[0].getInputStream());
},调度程序)
.applytoother(createTimeoutFuture(DURATION),Function.identity())
.例外情况下(可丢弃->{
processHolder[0]。强制销毁();
if(TimeoutException的可丢弃实例){
抛出新的DatasourceTimeoutException(可丢弃);
}
PropagativeInstanceof(throwable,DatasourceException.class);
抛出新的DatasourceException(throwable);
});
}
我看到的问题是一个“黑”的单元素数组,它保存对进程的引用,以便在出错时关闭它。是否有一些CompletableFuture
API允许异常地将一些“上下文”传递给(或者其他方法来实现)
我正在考虑定制CompletionStage
实现,但摆脱“holder”变量似乎是一项艰巨的任务。不需要有CompletableFuture
s的线性链。实际上,由于createTimeoutFuture(DURATION)
对于实现超时来说非常复杂,所以您已经没有了。你可以简单地这样说:
public CompletableFuture<ExecutionContext> createFuture() {
CompletableFuture<Process> proc=CompletableFuture.supplyAsync(
() -> {
try {
return new ProcessBuilder(COMMAND).redirectErrorStream(true).start();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}, SCHEDULER);
CompletableFuture<ExecutionContext> result
=proc.thenApplyAsync(process -> PARSER.parse(process.getInputStream()), SCHEDULER);
proc.thenAcceptAsync(process -> {
if(!process.waitFor(DURATION, TimeUnit.WHATEVER_DURATION_REFERS_TO)) {
process.destroyForcibly();
result.completeExceptionally(
new DatasourceTimeoutException(new TimeoutException()));
}
});
return result;
}
public CompletableFuture createFuture(){
CompletableFuture proc=CompletableFuture.SupplySync(
() -> {
试一试{
返回新的ProcessBuilder(命令).redirectErrorStream(true).start();
}捕获(IOE异常){
抛出新的未选中异常(e);
}
},调度器);
可完成的未来结果
=proc.thenappyasync(process->PARSER.parse(process.getInputStream()),调度器);
进程同步(进程->{
if(!process.waitFor(持续时间,时间单位,无论持续时间指什么)){
进程。强制销毁();
结果完全异常(
新数据源TimeoutException(new TimeoutException());
}
});
返回结果;
}
如果你想保持超时的未来,也许你认为流程启动时间是重要的,你可以使用
public CompletableFuture<ExecutionContext> createFuture() {
CompletableFuture<Throwable> timeout=createTimeoutFuture(DURATION);
CompletableFuture<Process> proc=CompletableFuture.supplyAsync(
() -> {
try {
return new ProcessBuilder(COMMAND).redirectErrorStream(true).start();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}, SCHEDULER);
CompletableFuture<ExecutionContext> result
=proc.thenApplyAsync(process -> PARSER.parse(process.getInputStream()), SCHEDULER);
timeout.exceptionally(t -> new DatasourceTimeoutException(t))
.thenAcceptBoth(proc, (x, process) -> {
if(process.isAlive()) {
process.destroyForcibly();
result.completeExceptionally(x);
}
});
return result;
}
public CompletableFuture createFuture(){
CompletableFuture timeout=CreateTimeouture(持续时间);
CompletableFuture proc=CompletableFuture.SupplySync(
() -> {
试一试{
返回新的ProcessBuilder(命令).redirectErrorStream(true).start();
}捕获(IOE异常){
抛出新的未选中异常(e);
}
},调度器);
可完成的未来结果
=proc.thenappyasync(process->PARSER.parse(process.getInputStream()),调度器);
超时。异常情况(t->new DatasourceTimeoutException(t))
.Then接受两者(proc,(x,process)->{
if(process.isAlive()){
进程。强制销毁();
结果:异常完全(x);
}
});
返回结果;
}
我自己也使用了一项数组来模拟Java中合适的闭包
另一个选项是使用带有字段的私有静态类。其优点是,它使目的更加明确,并且对具有大闭包的垃圾收集器(即具有N个字段的对象与长度为1的N个数组的对象)的影响较小。如果您需要在其他方法中关闭相同的字段,它也会很有用
这是一种事实上的模式,甚至超出了CompletableFuture
的范围,而且早在lambda成为Java中的一种东西之前(ab)就已经使用过,例如匿名类。所以,不要觉得很糟糕,只是Java的发展没有为我们提供合适的闭包(至今?是否?)
如果需要,您可以从.handle()
中的CompletableFuture
s返回值,这样您就可以将完成结果完整包装并返回包装器。在我看来,这并不比手动闭包好多少,并补充了一个事实,即您将在将来创建这样的包装器
子类化CompletableFuture
不是必需的。您对改变其行为不感兴趣,只对向其附加数据感兴趣,这可以通过当前Java的最终变量捕获来实现。也就是说,除非您分析并发现创建这些闭包实际上会以某种方式影响性能,我对此深表怀疑。第一个片段我不能使用,因为.waitFor
块,我想消耗可能非常大的InputStream
(因此.redirectErrorStream(true)
,我有“错误检测”后来,但那是另一个故事)。第二种方法似乎有点复杂(3个未来,包括CompletableFuture
),但我会尝试一下,它会阻塞异步操作。这就是“可接受同步”或“完全未来”阶段的全部要点;独立的阶段可以同时运行。这里,PARSER.parse
和process.waitFor
同时在独立的阶段运行。啊,我明白了。那我们就试试等待吧@霍尔格,第一种方法是,每次调用createFuture
都会阻塞一个超时线程。如果您实现createTimeoutFuture
中的任一计时器