我已经写了很多有关InterruptedException和中断线程的文章 。 简而言之,如果您没有Future.cancel()调用Future.cancel()那么Future将终止待处理的get() ,但还将尝试中断基础线程。 这是一个非常重要的功能,可以更好地利用线程池。 我还写信总是比标准Future更喜欢CompletableFuture 。 事实证明,功能更强大的Future弟兄没有那么优雅地处理cancel() 。 考虑以下任务,我们稍后将在整个测试中使用以下任务:

class InterruptibleTask implements Runnable {private final CountDownLatch started = new CountDownLatch(1)private final CountDownLatch interrupted = new CountDownLatch(1)@Overridevoid run() {started.countDown()try {Thread.sleep(10_000)} catch (InterruptedException ignored) {interrupted.countDown()}}void blockUntilStarted() {started.await()}void blockUntilInterrupted() {assert interrupted.await(1, TimeUnit.SECONDS)}}

客户端线程可以检查InterruptibleTask以查看其是否已开始或被中断。 首先,让我们看一下InterruptibleTask对外部的cancel()反应:

def "Future is cancelled without exception"() {given:def task = new InterruptibleTask()def future = myThreadPool.submit(task)task.blockUntilStarted()and:future.cancel(true)when:future.get()then:thrown(CancellationException)
}def "CompletableFuture is cancelled via CancellationException"() {given:def task = new InterruptibleTask()def future = CompletableFuture.supplyAsync({task.run()} as Supplier, myThreadPool)task.blockUntilStarted()and:future.cancel(true)when:future.get()then:thrown(CancellationException)
}

到目前为止,一切都很好。 显然, FutureCompletableFuture工作方式几乎相同-在取消结果后检索结果会引发CancellationException 。 但是myThreadPool线程呢? 我以为它会被游泳池打断,从而被回收,我怎么了!

def "should cancel Future"() {given:def task = new InterruptibleTask()def future = myThreadPool.submit(task)task.blockUntilStarted()when:future.cancel(true)then:task.blockUntilInterrupted()
}@Ignore("Fails with CompletableFuture")
def "should cancel CompletableFuture"() {given:def task = new InterruptibleTask()def future = CompletableFuture.supplyAsync({task.run()} as Supplier, myThreadPool)task.blockUntilStarted()when:future.cancel(true)then:task.blockUntilInterrupted()
}

第一个测试将普通的Runnable提交给ExecutorService并等待其启动。 稍后,我们取消Future并等待直到观察到InterruptedException 。 当基础线程被中断时, blockUntilInterrupted()将返回。 但是,第二次测试失败。 CompletableFuture.cancel()永远不会中断基础线程,因此尽管Future看起来好像已被取消,但后备线程仍在运行,并且sleep()不会抛出InterruptedException 。 错误或功能? 它已记录在案 ,因此很遗憾地提供一个功能:

参数: mayInterruptIfRunning –此值在此实现中无效,因为不使用中断来控制处理。

您说RTFM,但是为什么CompletableFuture这样工作? 首先,让我们研究“旧的” Future实现与CompletableFuture有何不同。 从ExecutorService.submit()返回的FutureTask具有以下cancel()实现(我使用类似的非线程安全Java代码删除了Unsafe ,因此仅将其视为伪代码):

public boolean cancel(boolean mayInterruptIfRunning) {if (state != NEW)return false;state = mayInterruptIfRunning ? INTERRUPTING : CANCELLED;try {if (mayInterruptIfRunning) {try {Thread t = runner;if (t != null)t.interrupt();} finally { // final statestate = INTERRUPTED;}}} finally {finishCompletion();}return true;
}

FutureTask具有一个遵循该状态图的state变量:

在的情况下, cancel()我们可以进入CANCELLED状态或去INTERRUPTED通过INTERRUPTING 。 核心部分是我们拿runner线程(如果存在的,也就是说,如果当前正在执行的任务),我们尽量打断它。 该分支负责急切和强制中断已运行的线程。 最后,我们必须通知阻塞的所有线程Future.get()finishCompletion()这里无关紧要)。 因此,很明显,多大的Future取消已经运行的任务。 那CompletableFuture呢? cancel()伪代码:

public boolean cancel(boolean mayInterruptIfRunning) {boolean cancelled = false;if (result == null) {result = new AltResult(new CancellationException());cancelled = true;}postComplete();return cancelled || isCancelled();
}

令人失望的是,我们几乎没有将result设置为CancellationException ,而忽略了mayInterruptIfRunning标志。 postComplete()也有类似的作用finishCompletion() -在通知未来注册的所有悬而未决的回调。 它的实现相当令人不快(使用非阻塞式Treiber stack ),但是它绝对不会中断任何底层线程。

原因和含义

CompletableFuture情况下,有限的cancel()不是错误,而是设计决定。 CompletableFuture并非固有地绑定到任何线程,而Future几乎总是代表后台任务。 从零开始创建CompletableFuturenew CompletableFuture<>() )是完美的,其中根本没有要取消的底层线程。 我仍然不禁感到大多数CompletableFuture 都将具有关联的任务和后台线程。 在这种情况下, cancel()可能会出现故障。 我不再建议用CompletableFuture盲目地替换Future ,因为它可能会更改依赖cancel()的应用程序的行为。 这意味着CompletableFuture故意违反了Liskov替换原则 -这是需要考虑的严重问题。

翻译自: https://www.javacodegeeks.com/2015/03/completablefuture-cant-be-interrupted.html

CompletableFuture不能被打断相关推荐

  1. JUC并发编程-CompletableFuture

    CompletableFuture基本介绍 阻塞的方式和异步编程的设计理念相违背,而轮询的方式会消耗无畏的CPU资源.因此,JDK8设计出CompletableFuture 核心的四个静态方法(分为两 ...

  2. CompletableFuture:让你的代码免受阻塞之苦

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:https://juejin.cn/post/6844904024332828685 写在前面 通过阅读本篇文章你将了解到: ...

  3. 无语!你竟然连CompletableFuture都不知道,还天天说在jdk8原地踏步~

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:https://urlify.cn/ayaMBb 这篇文章介绍 Java 8 的 CompletionStage API和它的 ...

  4. 20个使用 Java CompletableFuture的例子

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者 | 鸟窝 来源 | https://urlify.cn/ay ...

  5. CompletableFuture CompletableFuture.supplyAsync 异常处理

    CompletableFuture CompletableFuture.supplyAsync 异常处理 参考文章: (1)CompletableFuture CompletableFuture.su ...

  6. 程序员,告诉他们被打断的真实代价

    对程序员来 说,打断是低效率的最大原因之一.说实话,这种情况可能对任何人来说都是这样,只是对程序员而言相更糟糕一些.我举个例子来解释吧,比如有一个做销售的 人,他的大部分时间可能就花在接打电话或者在不 ...

  7. java8异步_Java8新特性之:CompletableFuture

    一. CompletableFuture 1.Future接口 Future设计的初衷:对将来某个时刻会发生的结果进行建模. 它建模了一种异步计算,返回一个执行运算结果的引用,当运算结束后,这个引用被 ...

  8. c++ 异步下获取线程执行结果_异步编排(CompletableFuture异步调用)

    1.问题背景 问题:当查询接口较复杂时候,数据的获取都需要远程调用,必然需要花费更多的时间. 假如查询文章详情页面,需要如下标注的时间才能完成: 那么,用户需要4s后才能统计的数据.很显然是不能接受的 ...

  9. CompletableFuture框架

    CompletableFuture除了含有可以直接操作任务状态和结果的方法外,还实现了CompletionStage接口的一些方法. 当CompletableFuture任务完成后,同步使用任务执行线 ...

最新文章

  1. C语言 带比较器的归并排序
  2. 解决 王爽写的汇编语言的第七个验七- 寻址方式在结构化数据访问中的应用
  3. 信息与计算机科学好学吗,计算机科学与技术好学吗?
  4. linux下top命令参数解释
  5. 闲来无事,做了个简单的在线编辑的mock服务
  6. 免费开源的 .NET 分布式组件库 Exceptionless Foundatio
  7. python求一元三次方程的根_初中数学专题复习-方程与方程组
  8. 花式迎新 百度李彦宏Robin化身大厨派发肉饼
  9. 自己封装的一个模拟下拉列表的插件
  10. Echarts异步获取数据不显示问题
  11. MongoDB复制集同步慢问题分析
  12. 互联网日报 | 贾跃亭宣布破产重组完成;小米发布首款OLED电视;湖南迎来首家本土航空公司...
  13. css样式,鼠标移动上去变成禁用、小手等样式。
  14. Linux的命名空间
  15. 【毕业设计】单片机智能鱼缸系统 - 嵌入式 物联网 stm32
  16. 如何使用命令提示符轻松地将GPT转换为MBR而不会丢失数据?
  17. centos——记录一次开机启动设置
  18. 二、HTML5 + CSS3 学习笔记
  19. 苹果手机里的照片导入电脑
  20. 如何提高项目估算精准度 关键有3方面

热门文章

  1. android拦截短信获取短信内容,《英雄联盟手游》先锋测试招募说明:仅安卓用户...
  2. win10安装dockerx docker的常见命令 可以子腾讯云上做做练习
  3. 阿里云服务器 window server tomcat启动 并且关闭window防火墙 配置8080端口开放还是没用
  4. java下载图片到手机相册_Unity保存图片到Android手机且更新相册
  5. SpringBoot整合Redis要注意的那些
  6. dmn是大脑中哪个区域_DMN中的函数式编程:感觉就像再次重读我的大学课程一样...
  7. 托管 非托管_如何在托管的Kubernetes上备份Neo4J
  8. vim 命令模式 筛选_10个步骤的筛选器模式
  9. graalvm_GraalVM上的Picocli:极快的命令行应用程序
  10. 网络研讨室_网络研讨会:Java 9的第一印象–构建可伸缩企业应用程序的新方法...