Java多线程处理List问题
作者:JonTang
这篇文章主要介绍了Java多线程处理List问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
Java多线程处理List
项目场景
调用第三方提供的接口去获取 List 中用户的组信息。
问题描述
需要拿用户的 id 去调用第三方接口,成功调用一次需要 0.3s 左右,当有 1000 个用户时,就需要花费 0.3 * 1000s = 5min,页面就会一直加载那么久。
之前是通过 for 循环 list 去调用接口的,
代码如下:
// 当 list 长度为 1000时,则需要循环 1000次 for(User user : list) { loadUserGroups(user); }
解决方案
通过多线程的方式去处理,话不多说直接上代码:
// 定义一个线程池 private static final ExecutorService loadUserGroupsExecutor = Executors.newFixedThreadPool(20); public Map<String, List<UserGroup>> loadAllUserGroups() { Map<String, List<UserGroup>> userGroups = new ConcurrentHashMap<>(); List<User> users = listUsers(); int size = users.size(); long startTime = System.currentTimeMillis(); if (size > 200) { List<List<User>> partition = Lists.partition(users, 200); List<CompletableFuture> results = new ArrayList<>(); for (List<User> subList : partition) { CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { loadUserGroups(userGroups, subList); return ""; }, loadUserGroupsExecutor); results.add(future); } CompletableFuture.allOf(results.toArray(results.toArray(new CompletableFuture[partition.size()]))).join(); } else { loadUserGroups(userGroups, users); } log.info("loadAllUserGroups cost {}", System.currentTimeMillis() - startTime); return userGroups; }
Java多线程分段处理List集合
场景:
大数据List集合,需要对List集合中的数据同标准库中数据进行对比,生成新增,更新,取消数据
解决方案
- List集合分段
- 动态创建线程池newFixedThreadPool
- 将对比操作在多线程中实现
public static void main(String[] args) throws Exception { // 开始时间 long start = System.currentTimeMillis(); List<String> list = new ArrayList<String>(); for (int i = 1; i <= 3000; i++) { list.add(i + ""); } /*动态线程数方式*/ // 每500条数据开启一条线程 int threadSize = 500; // 总数据条数 int dataSize = list.size(); // 线程数,动态生成 int threadNum = dataSize / threadSize + 1; /*固定线程数方式 // 线程数 int threadNum = 6; // 总数据条数 int dataSize = list.size(); // 每一条线程处理多少条数据 int threadSize = dataSize / (threadNum - 1); */ // 定义标记,过滤threadNum为整数 boolean special = dataSize % threadSize == 0; // 创建一个线程池 ExecutorService exec = Executors.newFixedThreadPool(threadNum); // 定义一个任务集合 List<Callable<Integer>> tasks = new ArrayList<Callable<Integer>>(); Callable<Integer> task = null; List<String> cutList = null; // 确定每条线程的数据 for (int i = 0; i < threadNum; i++) { if (i == threadNum - 1) { if (special) { break; } cutList = list.subList(threadSize * i, dataSize); } else { cutList = list.subList(threadSize * i, threadSize * (i + 1)); } final List<String> listStr = cutList; task = new Callable<Integer>() { @Override public Integer call() throws Exception { //业务逻辑,循环处理分段后的list System.out.println(Thread.currentThread().getName() + "线程:" + listStr); //...... return 1; } }; // 这里提交的任务容器列表和返回的Future列表存在顺序对应的关系 tasks.add(task); } exec.invokeAll(tasks); // 关闭线程池 exec.shutdown(); System.out.println("线程任务执行结束"); System.out.println("执行任务消耗了 :" + (System.currentTimeMillis() - start) + "毫秒"); }
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。