怎么个批量获取异步任务?
看下面询价系统的实例代码:
如果异步查询电商S2的时间非常短,因为get()方法是阻塞方法,所以必须要等待f1.get()获取成功之后才可以向下执行。
ExecutorService executor = Executors.newFixedThreadPool(3); //创建线程池
// 异步向电商S1询价
Future<Integer> f1 = executor.submit( ()->getPriceByS1());
// 异步向电商S2询价
Future<Integer> f2 = executor.submit( ()->getPriceByS2());
// 异步向电商S3询价
Future<Integer> f3 = executor.submit( ()->getPriceByS3());
// 获取电商S1报价并保存
r=f1.get();
executor.execute(()->save(r));
// 获取电商S2报价并保存
r=f2.get();
executor.execute(()->save(r));
// 获取电商S3报价并保存
r=f3.get();
executor.execute(()->save(r));
那么怎么才可以获得先执行结束的任务结果呢?
其实CompletionService内部也是维护了一个阻塞队列,当任务执行结束就把任务的执行结果加入到阻塞队列中,不同的是它是把任务执行结果的Future对象加入到阻塞队列中了,而上面的代码是把任务的执行结果放入了队列中。
CompletionService的接口实现类是ExecutorCompletionService,这个实现类的构造方法有两个:
1. ExecutorCompletionService(Executor executor)
2. ExecutorCompletionService(Executor executor, BlockingQueue<Future<v>> completionQueue)
1.需要传入线程池。
2.除了需要传入一个线程池,还需要传入一个阻塞队列,任务的执行结果就是放在completionQueue队列中的。
如果不指定阻塞队列,默认使用无界的LinkedBlockQueue,任务执行结果的Future就是放在这里面的。
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 创建CompletionService
CompletionService<Integer> cs = new ExecutorCompletionService<>(executor);
// 异步向电商S1询价
cs.submit(()->getPriceByS1());
// 异步向电商S2询价
cs.submit(()->getPriceByS2());
// 异步向电商S3询价
cs.submit(()->getPriceByS3());
// 将询价结果异步保存到数据库
for (int i=0; i<3; i++) {
Integer r = cs.take().get(); //获取cs阻塞队列中的Future对象,然后获得结果int。
executor.execute(()->save(r));
}
CompletionService接口提供5个方法:
Future<V> submit(Callable<V> task);
Future<V> submit(Runnable task, V result);
Future<V> take() throws InterruptedException;
Future<V> poll();
Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
两个submit提交方法。
剩下的三个方法都与阻塞队列有关。take(),poll()方法都是从阻塞队列中获取并移除一个元素.
Dubbo中有一种Forking集群,在这种集群模式下,支持并行地调用多个查询服务,只要有一个服务返回结果,整个服务就可以返回了。
例如你需要一个地图的服务,为了保证高可用和高性能,你可以并行调用三个地图服务商的API,然后只要有一个服务返回,这个服务就可以返回了。
下面看代码实例:
geocoder(addr) {
//并行执行以下3个查询服务,
r1=geocoderByS1(addr);
r2=geocoderByS2(addr);
r3=geocoderByS3(addr);
//只要r1,r2,r3有一个返回
//则返回
return r1|r2|r3;
}
利用CompletionService实现Forking这种集群模式:
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 创建CompletionService
CompletionService<Integer> cs = new ExecutorCompletionService<>(executor);
// 用于保存Future对象
List<Future<Integer>> futures = new ArrayList<>(3);
//提交异步任务,并保存future到futures
futures.add( cs.submit(()->geocoderByS1()));//添加 异步任务返回的Future结果
futures.add( cs.submit(()->geocoderByS2()));
futures.add( cs.submit(()->geocoderByS3()));
// 获取最快返回的任务执行结果
Integer r = 0;
try {
// 只要有一个成功返回,则break
for (int i = 0; i < 3; ++i) {
r = cs.take().get();
//简单地通过判空来检查是否成功返回
if (r != null) {
break;
}
}
} finally {
//取消所有任务
for(Future<Integer> f : futures)
f.cancel(true);
}
// 返回结果
return r;
更多:邓新