文章目录
- 前言
- 一、多线程处理有序集合?
- 总结
前言
通过多线程,处理数据是一个快速提高处理的手段,那么当用多线程处理的时候,如果遇到有序集合怎么办?例如: 我想爬取一本小说,那么爬取完成后,需要的是 一个有序的章节小说,而非混乱的 章节,如何做呢?
一、多线程处理有序集合?
例如前言中说的,就是处理有序集合,但是一般情况下,多线程处理数据都是无序的,现在模拟这个场景,例如我要计算1-100的和,但是记住要有序!!
废话不多说,直接上代码:
public class 多线程处理顺序集合 {
@SneakyThrows
public static void main(String[] args) {
List<Future<Integer>> resultList = new ArrayList<>();
ExecutorService service = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
Future<Integer> submit = service.submit(new MyCallAbale(i));
resultList.add(submit);
}
service.shutdown();
Integer res = 0;
for (Future<Integer> integerFuture : resultList) {
Integer integer = integerFuture.get();
System.out.println(integer);
res += integer;
}
System.out.println(res);
}
static class MyCallAbale implements Callable<Integer> {
private Integer num;
public MyCallAbale(Integer num) {
this.num = num;
}
@Override
public Integer call() throws Exception {
Integer res = 0;
for (Integer i = num * 10+1; i <= (num + 1) * 10; i++) {
res += i;
}
return res;
}
}
}
- 我们利用线程池处理Executors
- 处理有序集合,切记做好拆分,就是每个线程处理的是一段数据,这样这段数据内部顺序即使是乱的也无所谓,因为我要做的是整体有序就好
- submit 中的 Callable 接口可以返回结果,利用此来得到每个线程的计算结果
- service.shutdown(); 停止当前线程,但是不会立即停止,而是等待所有任务都执行完毕才会停止;这样就保证了所有线程执行完毕
- 利用 Future 的get() 方法获取每个线程的执行结果,得到最终计算结果
- 可以看到,打印的顺序就是有序的,每段的和也是对的,这就是有序集合的多线程处理
总结
Executors 线程池虽好用,但是不建议直接使用,可以通过全局线程池配置,然后每次使用一个配置,否则各处单独使用线程池,很乱,其次当有问题后,也不好排查;
用完 Executors 记住一定要 service.shutdown(); 或者类似方法, 否则线程池一直存在,不结束;
这里其实我省略了对于list集合的拆分,或者隐形进行了拆分,其实具体拆分逻辑可以参考这篇文章:
传送门大概思路
- 根据已有数据,可以每个线程需要处理的数据量,进行计算
- 取余 为0 说明刚刚好分配完,那么线程数就是 总数/分配数 的商智
- 取余 不为0 说明 有多余一点的数据,那么总线程数 就是 总数/分配数 的 商值 +1
- 这样,总线程 数就确定了,然后开始分割集合,就是循环将符合每个线程的数据,分配给这个线程即可
- 然后根据分配好的任务,线程池执行就行了,与上文基本一致了