前言
当我们在工作中遇到需要通过程序处理大量数据或者一些耗时任务时,使用单线程处理效率非常低,这时候我们一般都会用多线程来处理,本篇详细讲解如何利用多线程来处理大量任务。
从任务的性质来讲,一般分为CPU密集型、I/O密集型、混合型、内存型等,不同类型的任务在利用线程池时需要设置不同的核心线程数来达到最佳效果,实际中大家根据任务情况选择合适的核心线程数,以下是示例:
说明
本例使用自定义线程池处理cpu密集型任务,假设有100个任务需要处理,每个任务耗时1s,根据核心线程数量(cpuCoreCnt)将任务拆分成cpuCoreCnt份,每份使用一个线程处理。大家可以将下述例子直接复制使用,线程池相关参数根据自身项目情况自行设置即可。
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* *author:你住过的屋檐
*/
@Slf4j
public class DataHandle {
static int cpuCoreCnt = Runtime.getRuntime().availableProcessors(); //获取服务器CPU核心数
static int corePoolSize = cpuCoreCnt; // 核心线程数
static int maximumPoolSize = cpuCoreCnt; // 最大线程数
static int keepAliveTime = 30; // 非核心线程的空闲存活时长(分钟)
static int queueCapacity = 9999; // 队列最大长度
public static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(queueCapacity);
static ThreadPoolExecutor threadPool;
static{
threadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MINUTES, queue);
}
/**
* 处理数据
* @param handleList
*/
public static void task(List<Integer> handleList){
//处理数据
handleList.forEach(item->{
try {
//模拟业务每条数据处理1s中
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
}
public static void main(String[] args) {
//数据集(假如有100条数据,每个数据处理需要1s)
List<Integer> dataList = new ArrayList<>();
for (int i =1; i <=100; i++) {
dataList.add(i);
}
log.info("当前cpu核数:{}",cpuCoreCnt);
//通过对核心数取余来计算每个线程需要处理的数据量大小
int size = dataList.size() % cpuCoreCnt > 0 ? dataList.size() / cpuCoreCnt +1 : dataList.size() / cpuCoreCnt;
// 用于存储所有任务的Future
List<Future> futureList = new ArrayList<>();
// 记录开始时间
long startTime = System.currentTimeMillis();
for (int i = 0; i < cpuCoreCnt; i++) {
//获取每个线程要处理的数据集
List<Integer> handleList = dataList.subList(i * size, Math.min(dataList.size(), i * size + size));
//创建异步任务添加到线程池,这里使用jdk8的CompletableFuture
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
//数据集处理任务
task(handleList);
}, threadPool);
//将CompletableFuture添加到futureList用于计算耗时
futureList.add(completableFuture);
}
// 非阻塞等待所有任务完成
CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0])).thenRunAsync(() -> {
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println("处理完成,耗时: " + totalTime + "毫秒");
//关闭线程池
threadPool.shutdown();
}, threadPool);
}
}
执行结果
根据执行结果大概耗时13s,如果是单线程处理则需要100s,效率提升了数倍。
完结撒花,欢迎订阅专栏!