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)): ...
随机推荐
- 基于redis+lua实现高并发场景下的秒杀限流解决方案
转自:https://blog.csdn.net/zzaric/article/details/80641786 应用场景如下: 公司内有多个业务系统,由于业务系统内有向用户发送消息的服务,所以通过统 ...
- Ubuntu18.04LTS python3.6 cuda10.0 下安装低版本的pytorch
Ubuntu18.04LTS python3.6 cuda10.0 下安装低版本的pytorch,运行Hypergraph Neural Networks(HGNN) https://github.c ...
- [Linux] 树莓派 4B 安装 Ubuntu 19.10 (Eoan Ermine) IOT 版
硬件:Raspberry Pi 4B系统:Ubuntu 19.10 (Eoan Ermine) for IOT官网:https://ubuntu.com/download/iot/raspberry- ...
- Google Colab——零成本玩转深度学习
前言 最近在学深度学习HyperLPR项目时,由于一直没有比较合适的设备训练深度学习的模型,所以在网上想找到提供模型训练,经过一段时间的搜索,最终发现了一个谷歌的产品--Google Colabora ...
- Flask源码之:路由加载
路由加载整体思路: 1. 将 url = /index 和 methods = [GET,POST] 和 endpoint = "index"封装到Rule对象 2. 将Ru ...
- DRF框架(五)——context传参,二次封装Response类,两个视图基类(APIView/GenericAPIView),视图扩展类(mixins),子类视图(工具视图),视图集(viewsets),工具视图集
复习 1.整体修改与局部修改 # 序列化get (给前端传递参数) #查询 ser_obj = ModelSerializer(model_obj) #只传递一个参数,默认是instance的参数,查 ...
- 虚拟机CentOS创建/使用快照
快照 1.什么是快照 说的直白一点,就是创建一个备份.当执行了不可逆的错误操作后,可以通过快照用来恢复系统 2.创建快照的三种模式 挂载状态下创建快照 开机状态下创建快照 关机状态下创建快照 3.如何 ...
- delphi xe6 JSON 测试
System.JSON ISuperJSOn mORMETJSON QJSON 测试 我在测试时发现系统自带的JSON 占用内存大一但多了就会出现内存泄漏的问题 我用的Flst< ...
- ElasticSearch动态修改副本个数
创建只有 一个主分片,没有副本的小索引: PUT /my_temp_index{ "settings": { "number_of_shards" : 1, & ...
- springboot使用HttpSessionListener 监听器统计当前在线人数
概括: request.getSession(true):若存在会话则返回该会话,否则新建一个会话. request.getSession(false):若存在会话则返回该会话,否则返回NULL ht ...