ListenableFuture异步多线程代码实现
来源:互联网 发布:access数据库新技术 编辑:程序博客网 时间:2024/05/16 18:37
1、前言
随着软件开发的不断进步,在实际的开发应用中,可能一次请求需要查询若干次数据库或者调用若干次第三方,按照传统的串行执行的话,会大大增加响应时间,无法满足业务需求,更无法满足用户迫切需要响应迅速的愿望。对此,我们需要针对网络请求或内部调用中包含的“多任务”进行异步处理,并行去执行这些“任务”,这样就就会大大减小响应时间。本文是基于guava中的ListenableFuture来实现的。
2、代码说明
本文以多次查询数据库为例进行说明。为了能够模拟查询数据库,这里会事先创建一个map,将查询条件和查询结果封装到map中。
在batchExec方法中,传入带有泛型的查询条件集合,核心操作是遍历查询条件集合,将每一个查询条件传给SingleTask(业务实现类),SingleTask必需要实现callable接口,在call方法中实现查询业务,这里使用上面创建好的map来进行模拟操作。
对于每一个查询任务SingleTask,将其放入ListeningExecutorService的submit()方法中执行,会返回一个ListenableFuture对象,我们使用Futures的addCallback()方法对得到的ListenableFuture进行监听,如果success则得到查询结果,并将结果放入结果集合中。这里需要注意的是需要将每一个ListenableFuture单独存入一个集合中,使用Futures的allAsList()方法能够得到一个新的ListenableFuture对象,然后使用future的get()方法来阻塞这个ListenableFuture。这么做的原因是:必须等到所有的查询结果都返回后,才能返回最终的查询结果。
3、代码实现
代码实现如下所指示。希望对你有所帮助。
package future;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.Executors;import org.springframework.util.CollectionUtils;import com.google.common.util.concurrent.FutureCallback;import com.google.common.util.concurrent.Futures;import com.google.common.util.concurrent.ListenableFuture;import com.google.common.util.concurrent.ListeningExecutorService;import com.google.common.util.concurrent.MoreExecutors;/** * 基于ListenableFuture异步执行多任务模板 * 注意:需要引入guava包 * @author liqqc * * @param <V> */public class FutureDemo<V> { //线程池中线程个数 private static final int PoolSize = 50; //带有回调机制的线程池 private static final ListeningExecutorService service = MoreExecutors .listeningDecorator(Executors.newFixedThreadPool(PoolSize)); //模拟从数据库查询数据的操作,key为查询条件,value为查询结果 private static final Map<Integer,Person> persons = new HashMap<Integer,Person>(); static{ persons.put(1, new Person(1, "test1", 1, "aaa", 8888888888l)); persons.put(2, new Person(2, "test2", 2, "bbb", 8888888888l)); persons.put(3, new Person(3, "test3", 3, "ccc", 8888888888l)); persons.put(4, new Person(4, "test4", 4, "ddd", 8888888888l)); persons.put(5, new Person(5, "test5", 5, "eee", 8888888888l)); } public static void main(String[] args) throws Exception { FutureDemo<Person> futureDemo = new FutureDemo<Person>(); //增加查询条件 List<Integer> ids = new ArrayList<Integer>(); ids.add(1); ids.add(2); ids.add(3); ids.add(4); ids.add(5); //查询并得到结果 List<Person> batchExec = futureDemo.batchExec(ids); System.err.println(batchExec); } /** * * @param params 查询集合 * @return * @throws Exception */ public <T> List<V> batchExec(List<T> params) throws Exception { long start = System.currentTimeMillis(); if (CollectionUtils.isEmpty(params)) { return null; } final List<V> value = new ArrayList<V>(); try { List<ListenableFuture<V>> futures = new ArrayList<ListenableFuture<V>>(); for (T t : params) { //将实现了callable的任务放入到线程池中,得到一个带有回调机制的ListenableFuture实例, //通过Futures.addCallback方法对得到的ListenableFuture实例进行监听,一旦得到结果就进入到onSuccess方法中, //在onSuccess方法中将查询的结果存入到集合中 ListenableFuture<V> sfuture = service.submit(new SingleTask<T>(t)); Futures.addCallback(sfuture, new FutureCallback<V>() { public void onSuccess(V result) { value.add(result); } public void onFailure(Throwable t) { throw new RuntimeException(t); } }); //将每一次查询得到的ListenableFuture放入到集合中 futures.add(sfuture); } //这里将集合中的若干ListenableFuture形成一个新的ListenableFuture //目的是为了异步阻塞,直到所有的ListenableFuture都得到结果才继续当前线程 //这里的时间取的是所有任务中用时最长的一个 ListenableFuture<List<V>> allAsList = Futures.allAsList(futures); allAsList.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.err.println("总的执行时间: " + (System.currentTimeMillis() - start)); return value; } /** * 业务实现类 * @author liqqc * * @param <T> */ class SingleTask<T> implements batchFuture<T, V> { private T t; public SingleTask(T t) throws Exception { this.t = t; } public V call() throws Exception { //具体的查询操作,需要自己实现 int millis = (int) (Math.random() * 1000); Thread.sleep(millis); System.err.println("执行时的时间:" + System.currentTimeMillis() + " 随机sleep的时间:" + millis); return (V) persons.get(t); } } //必须继承Callable //可以增加业务需要的接口 interface batchFuture<T, V> extends Callable<V> { } //数据库中的实体bean static class Person { private int id; private String name; private int age; private String address; private long telephone; public Person(){} public Person(int id, String name, int age, String address, long tel){ this.id = id; this.name = name; this.age = age; this.address = address; this.telephone = tel; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public long getTelephone() { return telephone; } public void setTelephone(long telephone) { this.telephone = telephone; } }}
后来想了想代码不完全通用。改进后的代码实现如下所指示。
package future;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.Executors;import org.apache.commons.collections4.CollectionUtils;import com.google.common.util.concurrent.FutureCallback;import com.google.common.util.concurrent.Futures;import com.google.common.util.concurrent.ListenableFuture;import com.google.common.util.concurrent.ListeningExecutorService;import com.google.common.util.concurrent.MoreExecutors;/** * * @author liqqc * * @param <T> * @param <V> */public class MutiFutureTask<T,V> { private static final int PoolSize = 20; //带有回调机制的线程池 private static final ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(PoolSize)); public static <T, V> List<V> batchExec(List<T> params, BatchFuture<T, V> batchFuture) { if(CollectionUtils.isEmpty(params)){ return null; } final List<V> value = new ArrayList<V>(); try{ List<ListenableFuture<V>> futures = new ArrayList<ListenableFuture<V>>(); for(T t : params){ //将实现了Callable的任务提交到线程池中,得到一个带有回调机制的ListenableFuture实例 ListenableFuture<V> sfuture = service.submit(new SingleTask<T, V>(t, batchFuture)); Futures.addCallback(sfuture, new FutureCallback<V>() { @Override public void onSuccess(V result) { value.add(result); } @Override public void onFailure(Throwable t) { throw new RuntimeException(t); } }); futures.add(sfuture); } ListenableFuture<List<V>> allAsList = Futures.allAsList(futures); allAsList.get(); }catch(InterruptedException e){ e.printStackTrace(); }catch(ExecutionException e){ e.printStackTrace(); } return value; } /** *业务实现类 * @param <T> * @param <V> */ private static class SingleTask<T, V> implements Callable<V>{ private T param; private BatchFuture<T, V> batchFuture; public SingleTask(T param, BatchFuture<T, V> batchFuture){ this.param = param; this.batchFuture = batchFuture; } @Override public V call() throws Exception { return batchFuture.callback(param); } } public interface BatchFuture<T,V>{ V callback(T param); }}class MutiFutureTaskTest { private static final Map<Integer,Person> persons = new HashMap<Integer,Person>(); static{ persons.put(1, new Person(1, "test1", 1, "aaa", 8888888888l)); persons.put(2, new Person(2, "test2", 2, "bbb", 8888888888l)); persons.put(3, new Person(3, "test3", 3, "ccc", 8888888888l)); persons.put(4, new Person(4, "test4", 4, "ddd", 8888888888l)); persons.put(5, new Person(5, "test5", 5, "eee", 8888888888l)); } public static void main(String[] args) { List<Integer> param = new ArrayList<Integer>(); param.add(1); param.add(2); param.add(3); param.add(4); param.add(5); List<Person> result = MutiFutureTask.batchExec(param, new MutiFutureTask.BatchFuture<Integer, Person>() { @Override public Person callback(Integer param) { return persons.get(param); } }); System.out.println(result.size()); }}//数据库中的实体beanclass Person { private int id; private String name; private int age; private String address; private long telephone; public Person(){} public Person(int id, String name, int age, String address, long tel){ this.id = id; this.name = name; this.age = age; this.address = address; this.telephone = tel; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public long getTelephone() { return telephone; } public void setTelephone(long telephone) { this.telephone = telephone; }}
- ListenableFuture异步多线程代码实现
- Guava之ListenableFuture(实现Java异步)
- Guava ListenableFuture实现异步非阻塞调用
- 从Java future 到 Guava ListenableFuture实现异步调用
- 多线程Future之Guava ListenableFuture
- ListenableFuture
- ListenableFuture
- ListenableFuture
- Guava ListenableFuture 实现多线程 先执行完线程任务 ,再来执行主线程
- Python多线程、异步+多进程爬虫实现代码
- 多线程异步实现(backgroundworker)
- 多线程学习-ListenableFuture使用介绍以及示例
- Java多线程实现异步调用
- 多线程实现异步,工作随便
- Java多线程实现异步调用
- 多线程异步TCP客户端实现
- Java多线程实现异步调用
- asio的异步多线程实现
- 影徒之始
- jquery通用tab选项卡
- iOS - Mac Cornerstone Merge操作方法
- 颜色表
- A summary of OpenGL ES 3.1 demos and samples
- ListenableFuture异步多线程代码实现
- 斯坦福大学卷积神经网络----Module 1 Lesson 3 优化
- servlet实现保存当前预览数据为rat文件
- JAVA多线程
- static_cast、dynamic_cast、const_cast和reinterpret_cast总结
- jdbc操作数据库Statement和prepareStatement的区别
- 定时任务
- spring boot tomcat配置
- JQuery基本知识框架思维导图(上)