背景
当项目中有获取n个模块的信息,之后进行多个模块信息合并的操作,可以使用多线程来实现,开启多个异步线程哪区多个模块数据。例如获取用户基础信息和获取用户账号信息,他们分别处于不同的表或者不同的数据库中。
图示如下
模拟代码
用户合并信息bean
import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; public class UserInfo implements Serializable { private int userId; private String userName; private String sex; private int age; private String password; private String hobby; private String phoneNumber; private BigInteger accountId; private BigDecimal accountDeposit; private String bankOfAccountId; private UserInfo(UserBuilder userBuilder){ this.userId = userBuilder.userBaseInfo.getUserId(); if (userBuilder.userBaseInfo.getUserName() != null) this.userName = userBuilder.userBaseInfo.getUserName(); if (userBuilder.userBaseInfo.getSex() != null) this.sex = userBuilder.userBaseInfo.getSex(); this.age = userBuilder.userBaseInfo.getAge(); if (userBuilder.userBaseInfo.getHobby() != null)this.hobby = userBuilder.userBaseInfo.getHobby(); if (userBuilder.userBaseInfo.getPassword() != null) this.password = userBuilder.userBaseInfo.getPassword(); if (userBuilder.userBaseInfo.getPhoneNumber() != null) this.phoneNumber = userBuilder.userBaseInfo.getPhoneNumber(); if (userBuilder.userAccountInfo.getAccountId() != null) this.accountId = userBuilder.userAccountInfo.getAccountId(); if (userBuilder.userAccountInfo.getBankOfAccountId() != null) this.bankOfAccountId = userBuilder.userAccountInfo.getBankOfAccountId(); if (userBuilder.userAccountInfo.getAccountDeposit() != null) this.accountDeposit = userBuilder.userAccountInfo.getAccountDeposit(); } /** * BeanBuilder能保证像重叠构造器模式那样的安全性, * 也能保证像JavaBeans模式那么好的可读性。这就是Builder模式的一种形式, * 不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器(或者静态工厂), * 得到一个builder对象。然后客户端在builder对象上调用类似于setter的方法, * 来设置每个相关的可选参数。最后,客户端调用无参的builder方法来生成不可变的对象。 * 这个builder是它构建类的静态成员类。 * */ public static class UserBuilder{ private UserBaseInfo userBaseInfo; private UserAccountInfo userAccountInfo; public UserBuilder() { } public UserBuilder userBaseInfo(UserBaseInfo val) { this.userBaseInfo = val; return this; } public UserBuilder userAccountInfo(UserAccountInfo val) { this.userAccountInfo = val; return this; } public UserInfo build() { return new UserInfo(this); } } }
用户基础信息bean
public class UserBaseInfo { private int userId; private String userName; private String sex; private int age; private String password; private String hobby; private String phoneNumber; public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getHobby() { return hobby; } public void setHobby(String hobby) { this.hobby = hobby; } public String getPhoneNumber() { return phoneNumber; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } }
用户账号信息bean
import java.math.BigDecimal; import java.math.BigInteger; public class UserAccountInfo { private int userId; private BigInteger accountId; private BigDecimal accountDeposit; private String bankOfAccountId; public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public BigInteger getAccountId() { return accountId; } public void setAccountId(BigInteger accountId) { this.accountId = accountId; } public BigDecimal getAccountDeposit() { return accountDeposit; } public void setAccountDeposit(BigDecimal accountDeposit) { this.accountDeposit = accountDeposit; } public String getBankOfAccountId() { return bankOfAccountId; } public void setBankOfAccountId(String bankOfAccountId) { this.bankOfAccountId = bankOfAccountId; } }
用户service接口
import java.util.List; public interface UserService { List<UserBaseInfo> getUserInfos(); List<UserAccountInfo> getUserAccountInfos(); }
用户service接口实现类
import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; public class UserServiceImpl implements UserService{ @Override public List<UserBaseInfo> getUserInfos() { Long startTime = System.currentTimeMillis(); List<UserBaseInfo> userBaseInfoList = new ArrayList<>(); UserBaseInfo userBaseInfo = null; for (int i = 0; i < 5000; i++) { userBaseInfo = new UserBaseInfo(); userBaseInfo.setUserId(i); userBaseInfo.setUserName("测试账号" + i); userBaseInfo.setAge(18); userBaseInfo.setHobby("唱、跳、rap、篮球"); userBaseInfo.setPassword("Test123!=" + i); userBaseInfo.setPhoneNumber("13111111111"); userBaseInfo.setSex("无"); userBaseInfoList.add(userBaseInfo); } System.out.println("userBaseInfoList size:" + userBaseInfoList.size()); System.out.println("获取用户base信息用时:" + (System.currentTimeMillis() - startTime)); return userBaseInfoList; } @Override public List<UserAccountInfo> getUserAccountInfos() { Long startTime = System.currentTimeMillis(); List<UserAccountInfo> userAccountInfoList = new ArrayList<>(); UserAccountInfo userAccountInfo = null; for (int i = 0; i < 5000; i++) { userAccountInfo = new UserAccountInfo(); userAccountInfo.setUserId(i); userAccountInfo.setAccountId(new BigInteger(String.valueOf(10000000 + i))); userAccountInfo.setAccountDeposit(new BigDecimal("1314520" + i)); userAccountInfo.setBankOfAccountId("中国银行"); userAccountInfoList.add(userAccountInfo); } System.out.println("获取用户account信息用时:" + (System.currentTimeMillis() - startTime)); return userAccountInfoList; } }
模拟客户端测试
import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; public class TestClient { public static void main(String[] args) { final UserService userBaseService = new UserServiceImpl(); long startTime = System.currentTimeMillis(); //单线程串行运行 //获取用户账户基本信息 List<UserAccountInfo> userAccountInfos = userBaseService.getUserAccountInfos(); //获取用户基本信息 List<UserBaseInfo> userInfos = userBaseService.getUserInfos(); System.out.println("单线程获取用户信息运行耗时:" + (System.currentTimeMillis() - startTime)); //合并用户账号和基本信息来完善用户信息 List<UserInfo> userInfoList = new ArrayList<>(); setUserInfoList(userAccountInfos, userInfos, userInfoList); //清空list userInfoList.clear(); System.out.println("-------------------------"); long startTimeV2 = System.currentTimeMillis(); //自定义线程池 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 2, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); List<UserBaseInfo> userBaseInfoList = new ArrayList<>(); List<UserAccountInfo> userAccountInfoArrayList = new ArrayList<>(); try { userBaseInfoList = threadPoolExecutor.submit(new Callable<List<UserBaseInfo>>() { @Override public List<UserBaseInfo> call() throws Exception { return userBaseService.getUserInfos(); } }).get(); //阻塞主线程,等待线程池线程执行完毕 userAccountInfoArrayList = threadPoolExecutor.submit(new Callable<List<UserAccountInfo>>() { @Override public List<UserAccountInfo> call() throws Exception { return userBaseService.getUserAccountInfos(); } }).get();//阻塞主线程,等待线程池线程执行完毕 } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } threadPoolExecutor.shutdown(); System.out.println("多线程运行耗时:" + (System.currentTimeMillis() - startTimeV2)); setUserInfoList(userAccountInfoArrayList, userBaseInfoList, userInfoList); } /** * 用户完整信息装配 * @param userAccountInfos * @param userBaseInfos * @param userInfoList */ public static void setUserInfoList(List<UserAccountInfo> userAccountInfos, List<UserBaseInfo> userBaseInfos, List<UserInfo> userInfoList){ Long startTime = System.currentTimeMillis(); userBaseInfos.stream().forEach(userInfo -> { userAccountInfos.stream().forEach(userAccountInfo -> { if (userInfo.getUserId() == userAccountInfo.getUserId()) { userInfoList.add(new UserInfo.UserBuilder().userBaseInfo(userInfo).userAccountInfo(userAccountInfo).build()); } }); }); // for (int i = 0; i < userBaseInfos.size(); i++) { // for (int i1 = i; i1 < userAccountInfos.size(); i1++) { // if (userBaseInfos.get(i).getUserId() == userAccountInfos.get(i1).getUserId()) { // userInfoList.add(new UserInfo.UserBuilder().userBaseInfo(userBaseInfos.get(i)).userAccountInfo(userAccountInfos.get(i1)).build()); // } // } // } System.out.println("用户完整信息装配花费:" + (System.currentTimeMillis() - startTime)); } }
运行结果
如上图所示,如果是大数据量下,优化效果是很显著的,使用自定义线程池、Callable和FutureTask结合使用,FutureTask中有get()方法,能阻塞住线程,等执行完了返回一个结果,主线程拿到结果才能继续往下执行。