踩坑场景
某个业务场景,需要用到多线程,设计上根据店铺做分片,使用了Lists.partion做切分。本意上是要切分成n个子列表,但是Lists.partion作用不是切分成n个列表,而是切分成m个列表,每个列表元素为n个。导致本来想4个线程执行,变成了几十个线程,无知坑了自己。
partion方法定义
/**
* Returns consecutive {@linkplain List#subList(int, int) sublists} of a list,
* each of the same size (the final list may be smaller). For example,
* partitioning a list containing {@code [a, b, c, d, e]} with a partition
* size of 3 yields {@code [[a, b, c], [d, e]]} -- an outer list containing
* two inner lists of three and two elements, all in the original order.
*
* <p>The outer list is unmodifiable, but reflects the latest state of the
* source list. The inner lists are sublist views of the original list,
* produced on demand using {@link List#subList(int, int)}, and are subject
* to all the usual caveats about modification as explained in that API.
*
* @param list the list to return consecutive sublists of
* @param size the desired size of each sublist (the last may be
* smaller)
* @return a list of consecutive sublists
* @throws IllegalArgumentException if {@code partitionSize} is nonpositive
*/
public static <T> List<List<T>> partition(List<T> list, int size) {
checkNotNull(list);
checkArgument(size > 0);
return (list instanceof RandomAccess)
? new RandomAccessPartition<>(list, size)
: new Partition<>(list, size);
}
自己写的工具类
为了实现切分成n个子列表,自己写了个工具类,代码和单测如下
工具类代码
package com.test;
import com.google.common.collect.Lists;
import lombok.experimental.UtilityClass;
import org.apache.commons.collections4.CollectionUtils;
import java.util.Collections;
import java.util.List;
/**
* 列表工具
* @author
* @date 2021/12/22
*/
@UtilityClass
public class CubeListUtil {
/**
* 把列表切分成n个子列表
* 不是均分的,最后一个子列表会兜底剩余的所有未分配的元素
*
* @param list 待拆分列表
* @param num 拆分子列表数量
* @param <T> 类型
* @return 子列表
*/
public <T> List<List<T>> subList(List<T> list, int num) {
if(CollectionUtils.isEmpty(list)) {
return Collections.emptyList();
}
if(num <= 1) {
return Collections.singletonList(list);
}
// 拆分数量大于列表数量,则拆分数量调整为列表数量
if(num > list.size()) {
num = list.size();
}
int start = 0;
int eachSize = list.size() / num;
List<List<T>> subLists = Lists.newArrayListWithCapacity(num);
for (int i = 1; i <= num; i++) {
int end = i == num ? list.size() : start + eachSize;
subLists.add(list.subList(start, end));
start += eachSize;
}
return subLists;
}
/**
* 把列表平均切分成n个子列表
* @param list 待拆分列表
* @param num 拆分子列表数量
* @param <T> 类型
* @return 子列表
*/
public <T> List<List<T>> meanSubList(List<T> list, int num) {
if(CollectionUtils.isEmpty(list)) {
return Collections.emptyList();
}
if(num <= 1) {
return Collections.singletonList(list);
}
// 拆分数量大于列表数量,则拆分数量调整为列表数量
if(num > list.size()) {
num = list.size();
}
int start = 0;
int eachSize = list.size() / num;
int rem = list.size() % num;
List<List<T>> subLists = Lists.newArrayListWithCapacity(num);
for (int i = 1; i <= num; i++) {
// 如果有余数,则增加1个
int extra = rem-- <= 0 ? 0 : 1;
int end = i == num ? list.size() : start + eachSize + extra;
subLists.add(list.subList(start, end));
start += eachSize + extra;
}
return subLists;
}
}
单测
package com.test;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
/**
* 列表工具单测
*
* @author
* @date 2021/12/22
*/
public class CubeListUtilTest {
private static final List<Integer> LIST = Lists.newArrayList(1, 2, 3, 4, 5);
@Test
public void subList_list5_num1() {
List<List<Integer>> lists = CubeListUtil.subList(LIST, 1);
Assert.assertEquals("列表数量不对", 1, lists.size());
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(1, 2, 3, 4, 5), lists.get(0)));
}
/**
* 5 / 2 = 2
* [1,2,3,4,5] -> [[1,2],[3,4,5]]
*/
@Test
public void subList_list5_num2() {
List<List<Integer>> lists = CubeListUtil.subList(LIST, 2);
Assert.assertEquals("列表数量不对", 2, lists.size());
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(1, 2), lists.get(0)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(3, 4, 5), lists.get(1)));
}
/**
* 5 / 3 = 1
* [1,2,3,4,5] -> [[1],[2],[3,4,5]]
*/
@Test
public void subList_list5_num3() {
List<List<Integer>> lists = CubeListUtil.subList(LIST, 3);
Assert.assertEquals("列表数量不对", 3, lists.size());
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(1), lists.get(0)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(2), lists.get(1)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(3,4,5), lists.get(2)));
}
/**
* 5 / 4 = 1
* [1,2,3,4,5] -> [[1],[2],[3],[4,5]]
*/
@Test
public void subList_list5_num4() {
List<List<Integer>> lists = CubeListUtil.subList(LIST, 4);
Assert.assertEquals("列表数量不对", 4, lists.size());
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(1), lists.get(0)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(2), lists.get(1)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(3), lists.get(2)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(4, 5), lists.get(3)));
}
@Test
public void subList_list5_num5() {
List<List<Integer>> lists = CubeListUtil.subList(LIST, 5);
Assert.assertEquals("列表数量不对", 5, lists.size());
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(1), lists.get(0)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(2), lists.get(1)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(3), lists.get(2)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(4), lists.get(3)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(5), lists.get(4)));
}
@Test
public void subList_list5_num6() {
List<List<Integer>> lists = CubeListUtil.subList(LIST, 6);
Assert.assertEquals("列表数量不对", 5, lists.size());
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(1), lists.get(0)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(2), lists.get(1)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(3), lists.get(2)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(4), lists.get(3)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(5), lists.get(4)));
}
@Test
public void meanSubList_list5_num0() {
List<List<Integer>> lists = CubeListUtil.meanSubList(LIST, 0);
Assert.assertEquals("列表数量不对", 1, lists.size());
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(1, 2, 3, 4, 5), lists.get(0)));
}
@Test
public void meanSubList_list5_num1() {
List<List<Integer>> lists = CubeListUtil.meanSubList(LIST, 1);
Assert.assertEquals("列表数量不对", 1, lists.size());
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(1, 2, 3, 4, 5), lists.get(0)));
}
/**
* [1,2,3,4,5] -> [[1,2,3],[4,5]]
*/
@Test
public void meanSubList_list5_num2() {
List<List<Integer>> lists = CubeListUtil.meanSubList(LIST, 2);
Assert.assertEquals("列表数量不对", 2, lists.size());
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(1, 2, 3), lists.get(0)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(4, 5), lists.get(1)));
}
/**
* 5 / 3 = 1 ; 5 % 3 = 2
* [1,2,3,4,5] -> [[1,2],[3,4],[5]]
*/
@Test
public void meanSubList_list5_num3() {
List<List<Integer>> lists = CubeListUtil.meanSubList(LIST, 3);
Assert.assertEquals("列表数量不对", 3, lists.size());
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(1, 2), lists.get(0)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(3, 4), lists.get(1)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(5), lists.get(2)));
}
/**
* 5 / 4 = 1 ; 5 % 4 = 1
* [1,2,3,4,5] -> [[1,2],[3],[4],[5]]
*/
@Test
public void meanSubList_list5_num4() {
List<List<Integer>> lists = CubeListUtil.meanSubList(LIST, 4);
Assert.assertEquals("列表数量不对", 4, lists.size());
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(1, 2), lists.get(0)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(3), lists.get(1)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(4), lists.get(2)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(5), lists.get(3)));
}
@Test
public void meanSubList_list5_num6() {
List<List<Integer>> lists = CubeListUtil.meanSubList(LIST, 6);
Assert.assertEquals("列表数量不对", 5, lists.size());
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(1), lists.get(0)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(2), lists.get(1)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(3), lists.get(2)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(4), lists.get(3)));
Assert.assertTrue(CollectionUtils.isEqualCollection(Lists.newArrayList(5), lists.get(4)));
}
}
其他
使用方法前应好好看注释文档