目录
项目场景
前台通过模板批量上传数据到后台
问题描述
后台使用常规方法处理数据,效率低下
解决方案:
使用多线程线程池实现
方法一:没有返回值,直接在任务里完成计算
package com.lwk.test;import java.util.ArrayList;import java.util.List;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;public class ThreadPoolExample { public static void main(String[] args) throws InterruptedException { // 创建一个包含 10 个线程的线程池 ExecutorService executorService = Executors.newFixedThreadPool(10); // 创建一个包含 10000 个元素的 List List list = new ArrayList<>(); for (int i = 0; i < 10001; i++) { list.add(i); } // 将 List 分成 10 个子 List,每个子 List 包含 1000 个元素 List> subLists = new ArrayList<>(); int subListSize = 1000; for (int i = 0; i < list.size(); i += subListSize) { subLists.add(list.subList(i, Math.min(i + subListSize, list.size()))); } // 提交每个子 List 的处理任务给线程池 for (List subList : subLists) { executorService.submit(new Task(subList)); } // 等待线程池中所有任务执行完毕 executorService.shutdown(); executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); // 打印处理结果 System.out.println("List size: " + list.size()); System.out.println("Sum of elements: " + Task.getSum()); } static class Task implements Runnable { private List list; private static long sum = 0; public Task(List list) { this.list = list; } @Override public void run() { long subSum = 0; for (int i : list) { subSum += i; } synchronized (Task.class) { sum += subSum; } } public static long getSum() { return sum; } }}
方法二:有返回值
除了创建线程池和分割 List 的过程外,主要的变化是将 Task 类改为实现 Callable 接口,并返回子 List 的和。使用 CompletionService 提交任务和获取任务执行结果,从而减少了线程池的等待时间,提高了执行效率。最后,将每个子 List 的和累加起来,打印处理结果。
package com.lwk.test;import java.util.ArrayList;import java.util.List;import java.util.concurrent.*;public class ThreadPoolExample2 { public static void main(String[] args) throws InterruptedException, ExecutionException { // 创建一个包含 10 个线程的线程池 ExecutorService executorService = Executors.newFixedThreadPool(10); // 创建一个 CompletionService,用于提交任务和获取任务执行结果 CompletionService completionService = new ExecutorCompletionService<>(executorService); // 创建一个包含 10000 个元素的 List List list = new ArrayList<>(); for (int i = 0; i < 10001; i++) { list.add(i); } // 将 List 分成 10 个子 List,每个子 List 包含 1000 个元素 List> subLists = new ArrayList<>(); int subListSize = 1000; for (int i = 0; i < list.size(); i += subListSize) { subLists.add(list.subList(i, Math.min(i + subListSize, list.size()))); } // 提交每个子 List 的处理任务给 CompletionService for (List subList : subLists) { completionService.submit(new Task(subList)); } // 获取每个任务的执行结果,并将结果累加起来 long sum = 0; for (int i = 0; i < subLists.size(); i++) { Future future = completionService.take(); sum += future.get(); } // 打印处理结果 System.out.println("List size: " + list.size()); System.out.println("Sum of elements: " + sum); // 关闭线程池 executorService.shutdown(); } static class Task implements Callable { private List list; public Task(List list) { this.list = list; } @Override public Long call() throws Exception { long subSum = 0; for (int i : list) { subSum += i; } return subSum; } }}
最后
如果改为项目中使用的话,需要将 【创建一个包含 10000 个元素的 List】改为自己的数据集即可!
需要注意的是:在使用线程池时,需要选择合适的线程池大小,以避免创建过多的线程导致系统资源耗尽!
还有一点:也不要盲目的去开多个线程。如果你的服务器是单cpu单核开多线程反而会增加上下文损耗,从而降低程序执行效率。能开多少个线程,理论是这样计算的:逻辑cpu个数 = (物理cpu个数 * 每个cpu的核心数 * 超线程数),命令见如下:
查看物理cpu个数,也就是实物cpu的个数
cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l
查看每个cpu的core,也就是常说的核心数
cat /proc/cpuinfo| grep "cpu cores"| uniq
今天的分享就到这里了,如果问题欢迎留言指正!
来源地址:https://blog.csdn.net/kevinlcsdn/article/details/129381763