java中的异步处理和Feature接口(一)

背景介绍

想象这样一个场景:你可能希望为你的法国客户提供指定主题的热点报道。为实现这一功能,你需要向 谷歌或者Twitter的API请求所有语言中针对该主题最热门的评论,可能还需要依据你的内部算法 对它们的相关性进行排序。之后,你可能还需要使用谷歌的翻译服务把它们翻译成法语,甚至 利用谷歌地图服务定位出评论作者的位置信息,最终将所有这些信息聚集起来,呈现在你的网站上。

典型的“混聚”式应用

在这种“混聚”应用式的应用中,我们的应用可能会有以下两种需求:

  1. 由于我们调用的许多都是外部提供的接口,极有可能出现由于某些外部网络服务发生响应慢的情况。在这种情况下,我们可能希望依旧能为用户提供部分信息,比如提供带问号标记的通用地图,以文本的方式显示信息,而不是呆呆地显示一片空白屏幕,直到地图服务器返回结果或者超时退出。
  2. 要实现类似的服务,你需要与互联网上的多个Web服务通信。可是,你并不希望因为等待某 些服务的响应,阻塞应用程序的运行,浪费数十亿宝贵的CPU时钟周期。比如,不要因为等待 Facebook的数据,暂停对来自Twitter的数据处理。

以上两种场景体现了多任务程序设计的另一面。如果你的主要目标是在同一个CPU上执 行几个松耦合的任务,充分利用CPU的核,让其足够忙碌,从而最大化程序的吞吐量,那么你其实真正想做的是避免因为等待远程服务的返回,或者对数据库的查询,而阻塞线程的执行, 浪费宝贵的计算资源,因为这种等待的时间很可能相当长。这时就需要用到异步处理,在Java 5中提供的Future接口和在Java 8 中的新版实现CompletableFuture,就是处理这种情况的利器。

Feature接口

Future接口在Java 5中被引入,设计初衷是对将来某个时刻会发生的结果进行建模。它建模 了一种异步计算,返回一个执行运算结果的引用,当运算结束后,这个引用被返回给调用方。在 Future中触发那些潜在耗时的操作把调用线程解放出来,让它能继续执行其他有价值的工作, 不再需要呆呆等待耗时的操作完成。

Feature接口和Tread的区别

Future的优点是它比 更底层的Thread更易用。要使用Future,通常你只需要将耗时的操作封装在一个Callable对 象中,再将它提交给ExecutorService,就万事大吉了。

Feature接口示例

下面是一个Feature的demo示例:

    public void testFeature() {
        //创建Executor- Service,通 过它你可以 向线程池提 交任务
        ExecutorService executor = Executors.newCachedThreadPool();
        //向Executor- Service提交一个 Callable对象
        final Future<Double> futureRate = executor.submit(new Callable<Double>() {
            public Double call() {
                //以异步方式在新的线程中执行耗时的操作
                return doSomeLongComputation();
            }
        });
        //异步操作进行的同时你可以做其他的事情
        doSomethingElse();

        try {
            //获取异步操作的结果,如果最终被阻塞,无法得到结果,那么在最多等待1秒钟之后退出
            Double result = future.get(1, TimeUnit.SECONDS);
        } catch (ExecutionException e) {
            // 计算抛出一个异常
            e.printStackTrace();
        } catch (InterruptedException ie) { // 当前线程在等待过程中被中断
        } catch (TimeoutException te) { // 在Future对象完成之前超过已过期
        }
    }

使用Future以异步方式执行长时间的操作

如上图所示,这种编程方式让你的线程可以在ExecutorService以并发方式调 用另一个线程执行耗时操作的同时,去执行一些其他的任务。接着,如果你已经运行到没有异步 操作的结果就无法继续任何有意义的工作时,可以调用它的get方法去获取操作的结果。如果操 作已经完成,该方法会立刻返回操作的结果,否则它会阻塞你的线程,直到操作完成,返回相应 的结果。如果该长时间运行的操作永远不返回了会怎样?为了处理这种可能性,虽然Future提供了一个无需任何参数的get方法,我们还是推荐大家使用重 载版本的get方法,它接受一个超时的参数,通过它,你可以定义你的线程等待Future结果的最 长时间,从而无需永无止境的等待下去。

Feature接口的局限性

虽然Feature接口提供了方法来检测异步计算是否已经结束(使用 isDone方法),等待异步操作结束,以及获取计算的结果。但是这些特性还不足以让你编写简洁的并发代码。

我们可能还需要更多的特性来帮助我们写出更好异步代码,如:

  • 将两个异步计算合并为一个——这两个异步计算之间相互独立,同时第二个又依赖于第 一个的结果。
  • 等待Future集合中的所有任务都完成。
  • 仅等待Future集合中最快结束的任务完成(有可能因为它们试图通过不同的方式计算同一个值),并返回它的结果。
  • 通过编程方式完成一个Future任务的执行(即以手工设定异步操作结果的方式)。
  • 应对Future的完成事件(即当Future的完成事件发生时会收到通知,并能使用Future

计算的结果进行下一步的操作,不只是简单地阻塞等待操作的结果)。

下一节我们将介绍新的CompletableFuture类(它实现了Future接口)如何利用Java 8 的新特性以更直观的方式将上述需求都变为可能。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小灰灰

Quick-Task 动态脚本支持框架之结构设计篇

文章链接:https://liuyueyi.github.io/hexblog/2018/07/23/180723-Quick-Task-动态脚本支持框架之结构...

1023
来自专栏自然语言处理

数据分析:基于Python的自定义文件格式转换系统

无论读者现在是做数据挖掘、数据分析、自然语言处理、智能对话系统、商品推荐系统等等,都不可避免的涉及语料的问题即大数据。数据来源无非分为结构化数据、...

1642
来自专栏吴裕超

js和native交互方法浅析

一、背景 最近接触公司项目,需要和原生app做交互,由此业务需求,开始了学习探索之路。 二、解决方案之WebViewJavascriptBridge  想要和a...

3228
来自专栏SeanCheney的专栏

《Python分布式计算》 第6章 超级计算机群使用Python (Distributed Computing with Python)典型的HPC群任务规划器使用HTCondor运行Python任务

本章,我们学习另一种部署分布式Python应用的的方法。即使用高性能计算机(HPC)群(也叫作超级计算机),它们通常价值数百万美元(或欧元),占地庞大。 真正的...

1.3K10
来自专栏微信终端开发团队的专栏

Android安装包相关知识汇总

用户抱怨安装包越来越大?印度友人反馈装不上微信?欢迎来到本期的走进科学--安装包速成记。做一个有节操的安装包,我们希望它越小越好,并且确保用户都能安装的上。 A...

3928
来自专栏吉浦迅科技

DAY40:阅读Memory Fence Functions

The CUDA programming model assumes a device with a weakly-ordered memory model, ...

774
来自专栏记事本

Vtiger CRM 7.1 几处SQL注入漏洞分析

干白盒审计有小半年了,大部分是业务上的代码,逻辑的复杂度和功能模块结构都比较简单,干久了收获也就一般,有机会接触一个成熟的产品(vtiger CRM)进行白盒审...

4982
来自专栏喔家ArchiSelf

MCU上的代码执行时间

在许多实时应用程序中,二八原则并不生效,CPU 可以花费95%(或更多)的时间在不到5% 的代码上。电动机控制、引擎控制、无线通信以及其他许多对时间敏感的应用程...

872
来自专栏机器学习和数学

[编程经验]R语言入门及描述性统计分析方法

好吧,我承认,最近都没好好学习了,事情比较多,好几天晚上我都会写下标题,然后就没有然后了,今天再不能忍了,决定来一发。但是,我觉得还是推文的质量要比数量更加重要...

4025
来自专栏IT技术精选文摘

Android内存泄漏监控和优化技巧总结

2683

扫码关注云+社区