将List按照指定大小等分的几种实现方式和效率对比及优化

简介:   今天碰到一个需求,定时任务,批量从表里取数据并做一些其他操作然后再存表,每次取1000条,由于计算过程比较耗时所以要起多个线程同时跑,需要将List按照指定大小等分,如每100条数据起一个线程,若最后剩余一份不到100,也放到一个线程里,网络上的实现方法有很多,我测试之后理出三种相对比较好的实现...

  今天碰到一个需求,定时任务,批量从表里取数据并做一些其他操作然后再存表,每次取1000条,由于计算过程比较耗时所以要起多个线程同时跑,需要将List按照指定大小等分,如每100条数据起一个线程,若最后剩余一份不到100,也放到一个线程里,网络上的实现方法有很多,我测试之后理出三种相对比较好的实现方法,如下:

 1 /*第一种方法 思路比较简单,遍历list,将元素添加到subList,
 2 *每当i到pageSize的时候,将subList添加到listArray并新建,subList
 3 */
 4 public static <T> List<List<T>> splitList1(List<T> list, int pageSize) {
 5  
 6     List<List<T>> listArray = new ArrayList<List<T>>();
 7  
 8     List<T> subList = null;
 9  
10     for (int i = 0; i < list.size(); i++) {
11  
12         if (i % pageSize == 0) {
13  
14             subList = new ArrayList<T>();
15  
16             listArray.add(subList);
17  
18         }
19  
20         subList.add(list.get(i));
21  
22     }
23  
24     return listArray;
25  
26 }
/*第二种方法 思路和方法1差不多,遍历list,将元素添加到subList,
*当subList的size等于pageSize的时候,将subList添加到listArray并新建subList
*/
public static <T> List<List<T>> splitList2(List<T> list, int pageSize) {
 
    List<List<T>> listArray = new ArrayList<List<T>>();
 
    ArrayList<T> subList = new ArrayList<T>();
    for (T x : list) {
        subList.add(x);
        if (pageSize == subList.size()) {
            listArray.add(subList);
            subList = new ArrayList<T>();
        }
    }
 
    if (0 != subList.size()) {
        listArray.add(subList);
    }
 
    return listArray;
}
/*第三种方法,用到了java list自带的方法subList,
*先判断list的size<pageSize的情况,然后利用subList方法循环切块
*/
public static <T> List<List<T>> splitList3(List<T> list, int pageSize) {
    List<List<T>> listArray = new ArrayList<List<T>>();
    if (list != null && pageSize > 0) {
        int listSize = list.size();
        if (listSize <= pageSize) {
            listArray.add(list);
            return listArray;
        }
        int batchSize = listSize / pageSize;
        int remain = listSize % pageSize;
 
        for (int i = 0; i < batchSize; i++) {
            int fromIndex = i * pageSize;
            int toIndex = fromIndex + pageSize;
            listArray.add(list.subList(fromIndex, toIndex));
        }
        if (remain > 0) {
            listArray.add(list.subList(listSize - remain, listSize));
        }
    }
    return listArray;
}

  我从list的subList方法中得到灵感,也实现了一种方式,可读性稍好一些,如下:

/*我的思路也比较简单,就是遍历加切块,
*若toIndex大于list的size说明已越界,需要将toIndex设为list的size值
*/
public static <T> List<List<T>> splitList4(List<T> list, int pageSize) {
    List<List<T>> listArray = new ArrayList<List<T>>();
    for (int i = 0; i < list.size(); i+=pageSize) {
        int toIndex = i + pageSize>list.size()?list.size():i+pageSize;
        listArray.add(list.subList(i, toIndex));
    }
    return listArray;
}

  以上四种方法经过测试都可实现功能,如果List的size比较小,几十,几百,应该效率都差不多,那如果list的size很大,比如10万,100万,那么以上四种方式,哪一种效率最高呢,我简单测试了一下,pageSize设为20,list的size分别为10万,和100万,分别跑100次,然后取平均值,如下:

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList<Integer>();
 
    for (int i = 0; i < 100000; i++) {
        list.add(i);
    }
 
    Long time1 = System.currentTimeMillis();
    for (int i = 0; i <100 ; i++) {
        splitList1(list, 20);
    }
    Long time2 = System.currentTimeMillis();
    for (int i = 0; i <100 ; i++) {
        splitList2(list, 20);
    }
    Long time3 = System.currentTimeMillis();
    for (int i = 0; i <100 ; i++) {
        splitList3(list, 20);
    }
    Long time4 = System.currentTimeMillis();
    for (int i = 0; i <100 ; i++) {
        splitList3(list, 20);
    }
    Long time5 = System.currentTimeMillis();
 
 
    System.out.println("list的size为10000,执行100次,平均时间为:");
    System.out.println("方法1--->:" + (time2 - time1)/100.0+"ms");
    System.out.println("方法2--->:" + (time3 - time2)/100.0+"ms");
    System.out.println("方法3--->:" + (time4 - time3)/100.0+"ms");
    System.out.println("方法4--->:" + (time5 - time4)/100.0+"ms");
 
 
}

  执行结果为:

list的size为100000,执行100次,平均时间为:
方法1--->:2.86ms
方法2--->:2.08ms
方法3--->:0.66ms
方法4--->:0.43ms

    从执行结果中可以看到前两种方法效率,明显不如后两种,后两种时间相差不大,但看起来似乎方法4更好一些,再将list的size设为100万时,执行结果为:

list的size为1000000,执行100次,平均时间为:
方法1--->:21.65ms
方法2--->:14.09ms
方法3--->:0.95ms
方法4--->:0.57ms

  size设为1000万时,执行结果为:

list的size为1000000,执行100次,平均时间为:
方法1--->:138.39ms
方法2--->:112.86ms
方法3--->:6.63ms
方法4--->:6.07ms

  综上所看,方法4的效率稍好于方法3,方法2稍好于方法1,但3和4的效率比1和2要高出一个数量级,主要是因为方法1和2,是逐个设置的,很明显不如subList,在这里推荐方法4,代码简洁,稍微理解下,可读性也不错.


 

 

 

原文链接:https://www.imooc.com/article/41647
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作

相关文章
|
6月前
|
存储 NoSQL Redis
Redis第四弹,Redis实现list时候做出的优化ziplist(压缩链表,元素少的情况),可更好的节省空间list——(内部编码:quicklist)Object encoding
Redis第四弹,Redis实现list时候做出的优化ziplist(压缩链表,元素少的情况),可更好的节省空间list——(内部编码:quicklist)Object encoding
C++:模拟实现list及迭代器类模板优化方法
C++:模拟实现list及迭代器类模板优化方法
|
测试技术 数据安全/隐私保护
loadrunner 脚本优化-参数化之Parameter List参数同行取值
loadrunner 脚本优化-参数化之Parameter List参数同行取值
184 0
|
测试技术
loadrunner 脚本优化-参数化之Parameter List参数取值
loadrunner 脚本优化-参数化之Parameter List参数取值
152 0
|
Web App开发 测试技术 UED
Web交互设计优化的简易check list
Web交互设计优化的简易check list 00 | 时间: 2011-02-11 | 28,842 Views 交互设计, 用户研究   “优化已有产品的体验”,这是用户体验相关岗位职责中常见的描述。
1135 0
|
6月前
|
安全 Java
java线程之List集合并发安全问题及解决方案
java线程之List集合并发安全问题及解决方案
978 1
|
5月前
|
Java API Apache
怎么在在 Java 中对List进行分区
本文介绍了如何将列表拆分为给定大小的子列表。尽管标准Java集合API未直接支持此功能,但Guava和Apache Commons Collections提供了相关API。
|
5月前
|
运维 关系型数据库 Java
PolarDB产品使用问题之使用List或Range分区表时,Java代码是否需要进行改动
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。