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;    }}
1 0
原创粉丝点击