java异步回调和同步回调_使用Java 8的CompletableFuture进行功能样式的回调

java异步回调和同步回调

最近,在准备有关Java并行流的讨论时,我注意到经典文章“ 免费午餐结束 ”(TFLiO)已经过了十岁生日。 对于大多数程序员而言,本文及其伴随的宣传是他们的第一个警告,即处理器速度呈指数增长的40年趋势即将结束,实际上已经结束了。 用不同的趋势代替它,即增加每个芯片上的处理器数量,这意味着用赫伯·萨特(Herb Sutter)的话来说,程序员必须“从根本上转向并发”。

在TFLiO中,Sutter观察到绝大多数程序员“不依赖并发性”,但补充说“一旦抱怨了,基于锁的编程并不比OO难。” 第一个陈述无疑是正确的,但是基于锁的并发的十年经验却无法证实第二个陈述。 幸运的是,自从TFLiO发布时,Java 5才刚刚可用,并且它的高级并发实用程序就开始使用了,Java程序员基本上能够避免对其进行测试。 这些使Java开发人员几乎可以避免对同步和关键部分进行细粒度的推理。

从并发到并行,再到并行

Java 5并发库专注于异步任务处理,它基于生产者线程模型来创建任务,并通过阻塞队列将其移交给任务消费者。 在Java 7和8中,该模型得到了增强,它支持另一种任务执行样式,包括将任务数据集分解为子集,然后可以通过独立的同质子任务来处理每个子集。

这种样式的基本库是fork / join框架,它使程序员可以规定应如何拆分数据集,并支持将子任务提交到标准默认线程池。 “普通” ForkJoinPool 。 (在本文中,不合格的类和接口名称将引用程序包java.util.concurrent中的类型。)在Java 8中,通过并行流机制可以更轻松地访问fork / join并行性。 但是,并非所有问题都适用于这种并行处理方式:元素处理必须独立,数据集必须足够大,并且每个元素的处理成本要足够高才能进行并行加速,以补偿设置fork /加入框架。

同时,对Java 8中并行流的创新的关注已从对并发库的实质性添加(以CompletableFuture<T>类的形式)转移了注意力。 本文将探讨CompletableFuture ,以解释为什么它在依赖于不同的异类异步执行任务的交互的编程系统中如此有用,以及它如何补充fork / join样式的并行性,包括并行流。

页面渲染器

我们的起点将是从“ Java并发实践”(JCiP)中借用的示例,这是Java 5并发实用程序的经典说明。 在JCiP§6.3中,Brian Goetz探索了网页渲染器的开发,其每个页面的任务是渲染其文本以及下载和渲染其图像。 图像下载需要很长时间,在此期间,CPU除了等待外别无其他。 因此,显而易见的策略是通过首先启动其所有图像的下载,然后使用它们完成呈现页面文本之前的时间,最后呈现下载的图像来呈现页面。

页面渲染器的第一个JCiP版本使用Future的概念,该界面公开了允许客户端监视其他线程正在执行的任务进度的方法。 在清单1中,代表下载页面所有图像的任务的Callable提交给执行器,执行器返回一个Future,通过它可以查询下载任务的状态。 主线程完成页面文本的呈现后,将调用Future.get ,该方法将阻塞,直到所有下载的结果都可以作为List<ImageData>完全使用。 明显的缺点是下载任务的粗粒度性质。 在下载所有图像之前,没有图像可用于渲染。 接下来,我们将看到如何缓解该问题。

public void renderPage(CharSequence source) {
List<ImageInfo> info = scanForImageInfo(source);
// create Callable representing download of all images
final Callable<List<ImageData>> task = () ->
  info.stream()
    	.map(ImageInfo::downloadImage)
    	.collect(Collectors.toList());
	// submit download task to the executor
	Future<List<ImageData>> images = executor.submit(task);
	// renderText(source);
try {
   // get all downloaded images (blocking until all are available)
   final List<ImageData> imageDatas = images.get();
   // render images
   imageDatas.forEach(this::renderImage);
} catch (InterruptedException e) {
   // Re-assert the thread’s interrupted status
   Thread.currentThread().interrupt();
   // We don’t need the result, so cancel the task too
   images.cancel(true);
} catch (ExecutionException e) {
  throw launderThrowable(e.getCause()); }
}

清单1.使用Future等待所有图像下载

一些简化的假设使此示例及其后续变型易于管理:我们假设存在类型ImageInfo

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值