java中异步调用注意
Future接口是Java标准API的一部分,在java.util.concurrent包中。Future接口是Java线程Future模式的实现,可以来进行异步计算。
有了Future就可以进行三段式的编程了,1.启动多线程任务2.处理其他事3.收集多线程任务结果。从而实现了非阻塞的任务调用。在途中遇到一个问题,那就是虽然能异步获取结果,但是Future的结果需要通过isdone来判断是否有结果,或者使用get()函数来阻塞式获取执行结果。这样就不能实时跟踪其他线程的结果状态了,所以直接使用get还是要慎用,最好配合isdone来使用。如果直接使用get来获取结果, get是阻塞操作, 相当于获取结果仍然是同步.因此在获取结果的时候需要注意.
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Random;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Future;
- /**
- * 多线程执行,异步获取结果
- *
- * @author i-clarechen
- *
- */
- public class AsyncThread {
- public static void main(String[] args) {
- AsyncThread t = new AsyncThread();
- List<Future<String>> futureList = new ArrayList<Future<String>>();
- t.generate(3, futureList);
- t.doOtherThings();
- t.getResult(futureList);
- }
- /**
- * 生成指定数量的线程,都放入future数组
- *
- * @param threadNum
- * @param fList
- */
- public void generate(int threadNum, List<Future<String>> fList) {
- ExecutorService service = Executors.newFixedThreadPool(threadNum);
- for (int i = 0; i < threadNum; i++) {
- Future<String> f = service.submit(getJob(i));
- fList.add(f);
- }
- service.shutdown();
- }
- /**
- * other things
- */
- public void doOtherThings() {
- try {
- for (int i = 0; i < 3; i++) {
- System.out.println("do thing no:" + i);
- Thread.sleep(1000 * (new Random().nextInt(10)));
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- /**
- * 从future中获取线程结果,打印结果
- *
- * @param fList
- */
- public void getResult(List<Future<String>> fList) {
- ExecutorService service = Executors.newSingleThreadExecutor();
- service.execute(getCollectJob(fList));
- service.shutdown();
- }
- /**
- * 生成指定序号的线程对象
- *
- * @param i
- * @return
- */
- public Callable<String> getJob(final int i) {
- final int time = new Random().nextInt(10);
- return new Callable<String>() {
- @Override
- public String call() throws Exception {
- Thread.sleep(1000 * time);
- return "thread-" + i;
- }
- };
- }
- /**
- * 生成结果收集线程对象
- *
- * @param fList
- * @return
- */
- public Runnable getCollectJob(final List<Future<String>> fList) {
- return new Runnable() {
- public void run() {
- for (Future<String> future : fList) {
- try {
- while (true) {
- if (future.isDone() && !future.isCancelled()) {
- System.out.println("Future:" + future
- + ",Result:" + future.get());
- break;
- } else {
- Thread.sleep(1000);
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- };
- }
- }
优化获取方式:
List<Object> results = null;
int retryLimit = 3;
long delay = 10;
int tryTime = 0;
for(Future future : futures)
do {
try {
//此处原理:
results = future.get();
} catch (Exception e) {
results = null;
}
tryTime++;
if (results == null) {
try {
Thread.sleep(delay << tryTime);
} catch (InterruptedException e) {
}
}
} while (results == null && tryTime < retryLimit);
}
return results;
运行结果打印和future放入列表时的顺序一致,为0,1,2:
- do thing no:0
- do thing no:1
- do thing no:2
- Future:java.util.concurrent.FutureTask@68e1ca74,Result:thread-0
- Future:java.util.concurrent.FutureTask@3fb2bb77,Result:thread-1
- Future:java.util.concurrent.FutureTask@6f31a24c,Result:thread-2
使用CompletionService,它内部添加了阻塞队列,从而获取future中的值,然后根据返回值做对应的处理
下面是先执行完的线程先处理的方案:
- import java.util.Random;
- import java.util.concurrent.BlockingQueue;
- import java.util.concurrent.Callable;
- import java.util.concurrent.CompletionService;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.ExecutorCompletionService;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Future;
- import java.util.concurrent.LinkedBlockingDeque;
- public class testCallable {
- public static void main(String[] args) {
- try {
- completionServiceCount();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
- /**
- * 使用completionService收集callable结果
- * @throws ExecutionException
- * @throws InterruptedException
- */
- public static void completionServiceCount() throws InterruptedException, ExecutionException {
- ExecutorService executorService = Executors.newCachedThreadPool();
- CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(
- executorService);
- int threadNum = 5;
- for (int i = 0; i < threadNum; i++) {
- completionService.submit(getTask(i));
- }
- int sum = 0;
- int temp = 0;
- for(int i=0;i<threadNum;i++){
- temp = completionService.take().get();
- sum += temp;
- System.out.print(temp + "\t");
- }
- System.out.println("CompletionService all is : " + sum);
- executorService.shutdown();
- }
- public static Callable<Integer> getTask(final int no) {
- final Random rand = new Random();
- Callable<Integer> task = new Callable<Integer>() {
- @Override
- public Integer call() throws Exception {
- int time = rand.nextInt(100)*100;
- System.out.println("thead:"+no+" time is:"+time);
- Thread.sleep(time);
- return no;
- }
- };
- return task;
- }
- }
运行结果为最先结束的线程结果先被处理:
- thead:0 time is:4200
- thead:1 time is:6900
- thead:2 time is:2900
- thead:3 time is:9000
- thead:4 time is:7100
- 2 0 1 4 3 CompletionService all is : 10
java中异步调用注意的更多相关文章
- java中异步调用的解决方法
package demo.future; import java.util.ArrayList; import java.util.List; import java.util.concurrent. ...
- 在Java中直接调用js代码(转载)
http://blog.csdn.net/xzyxuanyuan/article/details/8062887 JDK1.6版添加了新的ScriptEngine类,允许用户直接执行js代码. 在Ja ...
- 在Java中直接调用js代码
JDK1.6版添加了新的ScriptEngine类,允许用户直接执行js代码. 在Java中直接调用js代码 不能调用浏览器中定义的js函数,会抛出异常提示ReferenceError: “alert ...
- 利用回调实现Java的异步调用
异步是指调用发出后,调用者不会立刻得到结果,而是在调用发出后,被调用者通知调用者,或通过回调函数处理这个调用. 回调简单地说就是B中有一个A,这样A在调用B的某个方法时实际上是调用到了自己的方法. 利 ...
- Java中如何调用静态方法
Java中如何调用静态方法: 1.如果想要调用的静态方法在本类中,可直接使用方法名调用 2.调用其他类的静态方法,可使用类名.方法名调用 关于静态方法能被什么调用 1.实例方法 2.静态发放
- java实现异步调用实例
在JAVA平台,实现异步调用的角色有如下三个角色: 调用者 取货凭证 真实数据 一个调用者在调用耗时操作,不能立即返回数据时,先返回一个取货凭证.然后在过一断时间后凭取货凭证来获取真正的数据. ...
- Java中异步注解@Async的陷阱
或许,你在Java后端添加异步过程时会这样处理,然后摇摇大摆.灰溜溜地闪,而实际的运行结果却并不是我们期望的那样.那么,现在就将试验结果记录如下,以便少走弯路. (一)在Controller层的公开接 ...
- Oracle存储过程中异步调用的实际操作步骤
本文标签:Oracle存储过程 我们都知道在Oracle数据库的实际应用的过程中,我们经常把相关的业务处理逻辑,放在Oracle存储过程中,客户端以通过ADO来进行相关的调用 .而有些相关的业务逻辑 ...
- java中如何调用oracle存储过程
在java中使用CallableStatement调用存储过程 列: 创建需要的测试表:create table Test(tid varchar2(10),tname varchar2(10)): ...
随机推荐
- Ubuntu下重启mysql
启动mysql: 方式一:sudo /etc/init.d/mysql start 方式二:sudo service mysql start 停止mysql: 方式一:sudo /etc/init.d ...
- 何为JavaScript原型?读完你就明白了
熟悉软件开发的朋友都知道,原型是产品或数据系统的一个基本的实用模型,通常为示范目的或开发程序的部份结构.原型的重要性不言而喻,接下来我就会为你讲解关于JavaScript中的原型概念.原型对象释义每一 ...
- Linux Docker Introduction
Setup on Ubuntu. 前提条件: Docker需要两个重要的安装要求: 它仅适用于64位Linux安装,注意:是64位的Linux系统. 它需要Linux内核版本3.10或更高版本. 要查 ...
- Word 去除文字底纹
有时候从网页复制的文字有底纹,如何清除呢? 未完 ...... 点击访问原文(进入后根据右侧标签,快速定位到本文)
- 什么是PHP?
PHP起源于1995年,由Rasmus Lerdorf开发.到现在,PHP已经历了21年的时间洗涤,成为全球最受欢迎的脚本开发语言之一.由于PHP 5是一种面向对象.完全跨平台的新型Web开发语言.所 ...
- mysql 注意小结
char 默认是1 个字符 char(12) 设置是12个字符 不管是中文还是英文或者数字只能有十二个 设置外键时,这时候外键对应的父键的字段要是主键 非空而且是唯一. create table t1 ...
- Zookeeper的典型应用场景(转)
在寒假前,完成了Zookeeper系列的前5篇文章,主要是分布式的相关理论,包括CAP,BASE理论,分布式数据一致性算法:2PC,3PC,Paxos算法,Zookeeper的相关基本特性,ZAB协议 ...
- CentOS7搭建jenkins
一.概述 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. 安装环境 操作系统:centos ...
- OpenFace 调试记录
1.OpenFace 是 卡耐基梅陇(CMU)大学的一个图像+机器学习项目,整体程序包含:人脸发现,特征提取,特征神经网络训练,人脸识别这四部分. github https://github.co ...
- 2019 携程旅行网java面试笔试题 (含面试题解析)
本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.蚂蚁金服等公司offer,岗位是Java后端开发,因为发展原因最终选择去了携程,入职一年时间了,也成为了面试官 ...