赞
踩
最近项目中有很多使用线程池进行处理的地方,同时也碰到了几个问题比如线程池的个数该怎么评估,线程程的该怎么具体去使用,结合项目和实际场景得到一些理解
通过指定核心和最大线程数大于1的方式来执行多个线程任务
适用场景:线程任务无需区分顺序,只需要有资源执行即可
new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MINUTES, queue, new ThreadFactoryBuilder()
.setNameFormat(threadKey)
.setUncaughtExceptionHandler((t, e) -> log.error("handler error: ", Thread.currentThread().getName(), e))
.build(), new DiscardPolicy());
使用map管理多个线程池
适用场景:适合任务需要顺序执行的场景,通过任务的唯一键进行hash获取对应的线程池对象
public static final Map<String, ExecutorService> map= new ConcurrentHashMap<>();
public static void execute(String key, Runnable runnable) {
String threadKey = key;
ExecutorService service = map.get(threadKey);
if (service == null) {
service = init(threadKey);
tsReciveThreadMap.put(threadKey, service);
}
service.execute(runnable);
}
启动独立的线程,使用LinkedBlockingQueue
循环等待接收消息
适用场景:适合批量等待处理一批数据的场景,循环等待一定时间,批量存储数据
public Map<String, BlockingQueue> queue = new HashMap<>();
public void init(ExecutorService executorService) {
for (int i = 0; i < 5; i++) {
LinkedBlockingQueue<T> blockingQueue = new LinkedBlockingQueue<>();
String key = i;
queue.put(key, blockingQueue);
executorService.execute(() -> {
while (true) {
try {
T take = blockingQueue.take();
Map<String, T> data = new HashMap<>();
data.put(take.getKey(), take);
long current = System.currentTimeMillis();
while (!blockingQueue.isEmpty() && data.size() < 100 && System.currentTimeMillis() - current < 1000) {
T take1 = blockingQueue.poll();
if (take1 != null) {
data.put(take1.getKey(), take1);
}
}
this.handleMessage(data);
} catch (Exception e) {
log.error("", e);
}
}
});
}
}
网上有一个比较广传的线程数设定公式
CPU 密集型的程序 - 核心数 + 1
I/O 密集型的程序 - 核心数 * 2
但是我们在设定线程数的时候,应该根据当前任务的具体逻辑来判断而不是使用网上这种通用公式。
以下有几个自己在项目中的实际体验
1.关注我们提交任务给线程池的流入速率
2.关注我们线程任务执行的流出速率
3.结合处理速率设定队列的大小
4.再结合运行环境实际CPU个数,超过这个个数大部分就没什么意义了
上面列出了在实际项目中使用的3种线程池的方式,使用线程池要结合业务场景以及
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。