【精】【多线程】ListenableFuture异步多线程查询实现

 

业务场景:为优化查询效率,将原有查询的条件做成单独的索引表,每次产生记录就会同步到索引表中,每次查询索引表,根据索引便利的条件字段再分别查询每张子表的内容,最后封装成前台要的实体类。这里面涉及到异步查询,如何保证一条记录下的子表全部都查出来后才执行下面的操作。

下面Demo简单演示下操作步骤:

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import org.junit.Test;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.ymdd.galaxy.report.utils.BeanCopierUtils;

public class ThredPoolTest {
	
	 private static ListeningExecutorService pool;
	 
	 static {
	        //通过guava创建固定容量的线程池,用完需要调用shutdown方法关闭线程池。
	        pool = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5));
	    }

	@Test
	public void test() throws InterruptedException, ExecutionException {
	    System.out.println("******用ListenableFuture异步操作******");
	    Instant now = Instant.now();
        Student student = new Student("元歌", "男", 12, "刺客");
        Person person = new Person();
        //将student和person相同的字段的值赋给person
        BeanCopierUtils.copyProperties(person, student);
        List<Student> studentList = new ArrayList<Student>();
        List<Person> personList = new ArrayList<Person>();
        ListenableFuture<List<Student>> studentFuture = pool.submit(() -> { 
        	  System.out.println("studentList 线程开始");
        	//这里使用了lambda表达式,
            for (int i = 0; i < 100000000; i++) { 
            	//也可以直接通过匿名内部类实现callable,runnable区别,一个有返回值,一个没有返回值
            	studentList.add(student);
            }
            System.out.println("studentList 线程结束");
            return studentList;
        });
        ListenableFuture<List<Person>> personFuture = pool.submit(() -> {
        	  System.out.println("personList 线程开始");
            for (int i = 0; i < 100000000; i++) {
            	personList.add(person);
            }
            System.out.println("personList 线程结束");
            return personList;
        });
        List<Student> sList = studentFuture.get();
		System.out.println("studentList获取");
		List<Person> pList = personFuture.get();
		System.out.println("personList获取");
        pool.shutdown();//用完之后关闭线程池
        Instant now1 = Instant.now();
        System.out.println(sList.size());
        System.out.println(pList.size());
        System.out.println("使用线程池耗时:"+Duration.between(now, now1).toMillis());

	}

	@Test
    public void test1() throws ExecutionException, InterruptedException {
	    System.out.println("******用普通For循环操作******");
        Instant now = Instant.now();
        Student student = new Student("司马懿", "男", 16, "刺客、法师");
        Person person = new Person();
        //将student和person相同的字段的值赋给person
        BeanCopierUtils.copyProperties(person, student);
        List<Student> studentList = new ArrayList<Student>();
        List<Person> personList = new ArrayList<Person>();
        for (int i = 0; i < 100000000; i++) {
        	studentList.add(student);
        }
        for (int i = 0; i < 100000000; i++) {
        	personList.add(person);
        }
        Instant now1 = Instant.now();
        System.out.println(studentList.size());
        System.out.println(personList.size());
        System.out.println("不使用线程池耗时:"+Duration.between(now, now1).toMillis());
    }

}

用到的工具和类:

Student、Preson类:

public class Student {

	private String name;
	private String sex;
	private Integer age;
	private String remark;
	
	public Student(String name,String sex,Integer age,String remark) {
		this.name=name;
		this.sex=sex;
		this.age=age;
		this.remark=remark;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public String getRemark() {
		return remark;
	}
	public void setRemark(String remark) {
		this.remark = remark;
	}
}
public class Person {

	private String name;
	private String sex;
	private Integer age;
	private String remark;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public String getRemark() {
		return remark;
	}
	public void setRemark(String remark) {
		this.remark = remark;
	}
}

 BeanCopierUtils工具类(Bean属性转换)

import java.util.HashMap;
import java.util.Map;
import net.sf.cglib.beans.BeanCopier;

public class BeanCopierUtils {

	public static Map<String, BeanCopier> beanCopierMap = new HashMap<String, BeanCopier>();  
      
    /**  
    * @Title: copyProperties  
    * @Description: TODO(bean属性转换)  
    * @param source 资源类 
    * @param target  目标类  
    * @author 050083
    * @date 2018年8月25日下午4:56:44
    */  
    public static void copyProperties(Object source,Object target){  
        String beanKey = generateKey(source.getClass(),target.getClass());  
        BeanCopier copier = null;  
        if (!beanCopierMap.containsKey(beanKey)) {  
            copier = BeanCopier.create(source.getClass(), target.getClass(), false);  
            beanCopierMap.put(beanKey, copier);  
        }else {  
            copier = beanCopierMap.get(beanKey);  
        }  
        copier.copy(source, target, null);  
    }  
    
    private static String generateKey(Class<?>class1,Class<?>class2){  
        return class1.toString() + class2.toString();  
    }  
}

执行结果如下:

对比结果不难发现ListenableFuture异步多线程操作要比普通的操作上不少。

下面给大家看一下我实际项目中的应用(多表查询的),代码如下:

// (1)数据库中单独查表
ListenableFuture<List<Order>> orderFuture = queryOrderListFuture(orderNos);
// 获取地址数据
ListenableFuture<List<OrderAddress>> addressFuture=queryOrderAddressListFuture(orderNos);
// 获取受理表数据
ListenableFuture<List<OrderAccept>> orderAcceptFuture=queryOrderAcceptListFuture(orderNos);
// 获取包装数据
ListenableFuture<List<OrderPackageRule>> orderPackageRuleFuture = queryOrderPackageRuleListFuture(orderNos);
// 获取订单服务费用表
ListenableFuture<List<OrderServiceFee>> orderServiceFeeFuture = queryOrderServiceFeeListFuture(orderNos);
// 获取优惠券表数据
ListenableFuture<List<OrderDiscount>> orderDiscountFuture = queryOrderDiscountFuture(orderNos);
// 保证所有查询执行完毕后才执行下面的业务代码
// (2)数据进行处理
List<OrderDetail> orderDetailList = null;
try {
	// 订单转换orderDetail
	orderDetailList = queryOrderData(null != orderFuture ? orderFuture.get() : null);
	// 获取地址数据
	queryOrderAddressData(null != addressFuture ? addressFuture.get() : null, orderDetailList);
	// 获取受理表数据
	queryOrderAcceptData(null != orderAcceptFuture.get() ? orderAcceptFuture.get() : null, orderDetailList);
	// 获取包装数据
	queryOrderPackageRuleData(null != orderPackageRuleFuture.get() ? orderPackageRuleFuture.get() : null,orderDetailList);
	// 获取订单服务费用表
	queryOrderServiceFeeData(null != orderServiceFeeFuture.get() ? orderServiceFeeFuture.get() : null,orderDetailList);
	// 获取优惠券表数据
	getOrderDiscountData(null != orderDiscountFuture.get() ? orderDiscountFuture.get() : null,orderDetailList);
	// LOGGER.info("查询订单处理完====六个表====后的数据:{}",JSON.toJSON(orderDetailList));
    } catch (InterruptedException | ExecutionException e) {
		e.printStackTrace();
}

用到的方法简单展示一个(其余类似):

    /***
	 * 通过订单号,获取订单信息
	 * 
	 * @param orderNos
	 * @return
	 */
	@Override
	public List<Order> queryOrderListByOrderNo(List<Long> orderNos) {
		OrderExample example = new OrderExample();
		com.ymdd.galaxy.order.entity.ord.model.OrderExample.Criteria createCriteria = example.createCriteria();
		if (CollectionUtils.isNotEmpty(orderNos) && orderNos.size() == 1) {
			createCriteria.andOrderNoEqualTo(orderNos.get(0));
		} else {
			createCriteria.andOrderNoIn(orderNos);
		}
		List<Order> orderList = this.selectByExample(example);
		return orderList;
	}

	/**
	 * 获取订单信息的ListenableFuture
	 */
	private ListenableFuture<List<Order>> queryOrderListFuture(List<Long> orderNos) {
		return pool.submit(() -> {
			return queryOrderListByOrderNo(orderNos);
		});
	}

       具体的实现就不详细介绍了,大家可以通过Demo自己测试玩下,再结合展示的部分业务代码,就能大概明白使用方法了。有疑问可以留言,也请各位大神不吝赐教!!!

猜你喜欢

转载自blog.csdn.net/weixin_38256991/article/details/82906097