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

 /*第一种方法 思路比较简单,遍历list,将元素添加到subList,
*每当i到pageSize的时候,将subList添加到listArray并新建,subList
*/
public static <T> List<List<T>> splitList1(List<T> list, int pageSize) { List<List<T>> listArray = new ArrayList<List<T>>(); List<T> subList = null; for (int i = 0; i < list.size(); i++) { if (i % pageSize == 0) { subList = new ArrayList<T>(); listArray.add(subList); } subList.add(list.get(i)); } return listArray; }
/*第二种方法 思路和方法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
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作

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

  1. 截取UIImage指定大小区域

    截取UIImage指定大小区域 最近遇到这样的需求:从服务器获取到一张照片,只需要显示他的左半部分,或者中间部分等等.也就是截取UIImage指定大小区域. UIImage扩展 我的解决方案是对UII ...

  2. C# 图片超过指定大小将压缩到指定大小不失真

    using System;using System.Collections.Generic;using System.Drawing;using System.Drawing.Drawing2D;us ...

  3. Linux下删除空文件,删除指定大小的文件

    Linux下批量删除空文件(大小等于0的文件)的方法: find . -name "*" -type f -size 0c | xargs -n 1 rm -f 用这个还可以删除指 ...

  4. 2016-08-15:从YUV420P中提取指定大小区域

    typedef struct { int width; int height; }SizeInfo; typedef struct { int x; int y; int width; int hei ...

  5. dd 生成指定大小文件

    d命令可以轻易实现创建指定大小的文件,如 dd if=/dev/zero of=test bs=1M count=1000 会生成一个1000M的test文件,文件内容为全0(因从/dev/zero中 ...

  6. PHP 生成指定大小随机图片

    PHP 生成指定大小随机图片 <?php $image_width = 100; $image_height = 100; $image_str = ''; if (isset($_GET['w ...

  7. PHP JS HTML ASP页面跳转代码 延时跳转代码 返回到上一界面并刷新 JS弹出指定大小的新窗口

    1.PHP延时跳转代码 //跳转到浏览界面 header("Refresh:1;url=machine_list.php"); //不延时 <?php header(&quo ...

  8. linux dd命令参数及用法详解---用指定大小的块拷贝一个文件(也可整盘备份)

    linux dd命令参数及用法详解---用指定大小的块拷贝一个文件 日期:2010-06-14 点击:3830 来源: 未知 分享至:            linux dd命令使用详解 dd 的主要 ...

  9. Delphi中建立指定大小字体和读取该字体点阵信息的函数(转)

    源:Delphi中建立指定大小字体和读取该字体点阵信息的函数 Delphi中建立指定大小字体和读取该字体点阵信息的函数 作者:Thermometer Email:  webmaster@daheng- ...

随机推荐

  1. 一文读懂Https的安全性原理、数字证书、单项认证、双项认证等

    本文引用了作者Smily(博客:blog.csdn.net/qq_20521573)的文章内容,感谢无私分享. 1.前言 目前苹果公司已经强制iOS应用必须使用HTTPS协议开发(详见<苹果即将 ...

  2. 【原创】PicUploader: 一个还不错的图床工具

    PicUploader PicUploader 是一个用php编写的图床工具,它能帮助你快速上传你的图片到云图床,并自动返回Markdown格式链接到剪贴板.配置完成后,要获取一个可用于markdow ...

  3. 基于.Net进行前端开发的技术栈发展路线(二)

    前言 上一篇<我的技能树>文章分享了我的技能成长过程,还未完成,今天继续跟大家分享. 01 我的技能树 我的当前的技能树: 其中,标注为黄色旗帜的是基本掌握,标注为红色旗帜的为使用熟练.未 ...

  4. WebService简单介绍(一)

    分布式系统或软件如何通信?使用WebService服务.说它是服务可以,web通信中间件也ok,web通信组件....... 特点 自包含 自描述 跨平台.跨语言 基于开放和标准 (用了xml,嗯,开 ...

  5. git合并两个不同的仓库

    目前开发是2个仓库,线上仓库online_a(对应的branch分支为online),测试环境online_b(对应的branch分支为demo),测试环境需要时刻保持onine_a上的最新稳定稳定代 ...

  6. "PECS原则"几篇好文章

    <? extends T>和<? super T>Java 泛型中的PECS原则(copy源码样例) ​

  7. Android破解学习之路(九)—— 练手破解游戏集合

    1.魔塔50层 https://www.taptap.com/app/48859 选择需要购买的东西,之后在支付宝支付界面点击取消,即可支付成功 2.布布合丁丁 https://www.coolapk ...

  8. 2018.12/6 js键盘事件 DOM:0级2级

    DOM0级事件元素绑定多个click最后只执行最后一个click. DOM2级事件元素绑定多个click,都要执行 注意当绑定的多个事件名,函数名,事件发生阶段三者完全一样时,才执行最后一个 div. ...

  9. springboot新手使用guns开源框架心得

    一.导航 以guns的通知管理为例 l  通知管理的请求地址是localhost:8080/notice l  程序收到这样的请求就去找地址为notice的Controller l  通知控制器收到这 ...

  10. jQuery实现简单的图片淡入淡出效果

    整体思路: 1.实现页面布局,设置css样式 2.用jQuery获取需要用到的变量 3.用jQuery为两个按钮绑定事件 一.页面布局: <div class="d1"> ...