Java多线程处理List问题

 更新时间:2023年09月21日 16:25:44   作者: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) + "毫秒");
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Spring @Async无法实现异步的解决方案

    Spring @Async无法实现异步的解决方案

    这篇文章主要介绍了Spring @Async无法实现异步的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Java采用setAsciiStream方法检索数据库指定内容实例解析

    Java采用setAsciiStream方法检索数据库指定内容实例解析

    这篇文章主要介绍了Java采用setAsciiStream方法检索数据库指定内容,是比较实用的功能,需要的朋友可以参考下
    2014-08-08
  • Java 中Json中既有对象又有数组的参数如何转化成对象(推荐)

    Java 中Json中既有对象又有数组的参数如何转化成对象(推荐)

    Gson库是一个功能强大、易于使用的Java序列化/反序列化库,它提供了丰富的API来支持Java对象和JSON之间的转换,这篇文章主要介绍了Java 中Json中既有对象又有数组的参数如何转化成对象,需要的朋友可以参考下
    2024-07-07
  • java swing实现简单的五子棋游戏

    java swing实现简单的五子棋游戏

    这篇文章主要为大家详细介绍了java swing实现简单的五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-03-03
  • java Lambda表达式的使用心得

    java Lambda表达式的使用心得

    这篇文章主要介绍了java Lambda表达式的使用心得,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Springboot基于maven打包分离lib及resource

    Springboot基于maven打包分离lib及resource

    这篇文章主要介绍了Springboot基于maven打包分离lib及resource,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • SpringSecurity中@PermitAll与@PreAuthorize的实现

    SpringSecurity中@PermitAll与@PreAuthorize的实现

    @PermitAll和@PreAuthorize都是处理安全性的强大工具,本文主要介绍了SpringSecurity中@PermitAll与@PreAuthorize的实现,具有一定的参考价值,感兴趣的可以了解一下
    2024-07-07
  • java整合微信支付功能详细示例

    java整合微信支付功能详细示例

    这篇文章主要给大家介绍了关于java整合微信支付功能的相关资料,支付是一个复杂且测试起来需要的配置特别复杂的模块,文中给出了详细的示例代码,需要的朋友可以参考下
    2023-07-07
  • Java Exception异常全方面分析

    Java Exception异常全方面分析

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等
    2022-03-03
  • Java 异常详解

    Java 异常详解

    本文主要介绍了异常与错误的区别,异常的体现分类,异常的处理机制,如何自定义异常等,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02

最新评论