线程池
一、Java线程池介绍
在Java中,线程池是一种管理和复用线程的机制,用于提高多线程应用程序的性能和资源利用率。线程池在执行任务时,可以避免频繁地创建和销毁线程,从而减少了系统开销,并且能够更有效地利用系统资源。Java中线程池的主要作用包括以下方面:
① 线程的复用:线程池会预先创建一定数量的线程,并将它们保存在池中。当有任务需要执行时,线程池会分配一个空闲的线程来执行任务,执行完毕后线程不会销毁,而是重新放入线程池中,等待下一个任务的到来。这种线程的复用避免了频繁地创建和销毁线程,提高了线程的利用率。
② 资源管理:线程池可以限制并发线程的数量,避免系统因为线程过多而导致资源耗尽或性能下降的问题。通过配置线程池的核心参数,可以控制线程数量的上限、空闲线程的存活时间等,从而更好地管理系统资源。
③ 任务调度:线程池可以用于执行各种类型的任务,包括周期性任务、延迟任务、定时任务等。通过使用不同类型的线程池和调度策略,可以灵活地调度任务的执行时间和执行方式,满足不同场景下的需求。
Java中线程池的实现主要依赖于java.util.concurrent包下的Executor接口及其子接口ExecutorService,以及ThreadPoolExecutor等具体实现类。开发人员可以通过这些接口和类来创建和管理线程池,并通过配置不同的参数来满足不同的需求。
线程配置
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorExample {
public static void main(String[] args) {
// 创建一个带有定时任务队列的ThreadPoolExecutor
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(10); // 设置队列大小为10
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
60L, // 线程存活时间
TimeUnit.SECONDS,
workQueue, // 任务队列
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);
// 设置队列大小
executor.setQueueCapacity(20);
// 关闭线程池
executor.shutdown();
}
}
使用
package com.test.thread.service.impl;
import com.test.thread.service.GameService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.ExecutorService;
/**
* @author清梦
* @site www.xiaomage.com
* @company xxx公司
* @create 2024-05-20 22:04
*/
@Service
@Slf4j
public class GameServiceImpl implements GameService {
@Resource
@Qualifier("gameExecutor")
private ExecutorService gameExecutor;
@Resource
@Qualifier("queueExecutor")
private ExecutorService queueExecutor;
@Override
public void testRun() {
for (int i=0;i<1000;i++){
log.info("############循环第"+i+"次###########");
gameExecutor.submit(()->{
log.info("############gameExecutor###########");
//业务流程
log.info("#####gameExecutor-----end");
});
}
}
@Override
public void testRunQueue() {
for (int i=0;i<1000;i++){
log.info("############循环第"+i+"次###########");
queueExecutor.submit(()->{
log.info("############queueExecutor###########");
//业务流程
log.info("#####queueExecutor----------end");
});
}
}
}
最大核心数设置
2、线程池核心线程数和最大线程数怎么设置?
分为CPU密集型和IO密集型
CPU这种任务消耗的主要是 CPU 资源,可以将线程数设置为 N(CPU 核心数)+1,比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其它原因导致的任务暂停而带来的影响。
IO密集型 这种任务应用起来,系统会用大部分的时间来处理 I/O 交互,而线程在处理 I/O 的时间段内不会占 用 CPU 来处理,这时就可以将 CPU 交出给其它线程使用。因此在 I/O 密集型任务的应用中,我们 可以多配置一些线程,具体的计算方法可以是 :核心线程数=CPU核心数量*2。
最大线程数 一般设置为核心线程数的2~3倍,这个数值是不固定的
实际工程经验可能并不是严格按照这个来的,我们要根据实际开发场景来设置。
3、如何获取CPU核数
Runtime.getRuntime().availableProcessors();