使用ThreadPoolExecutor自定义线程池
一.七大参数
- 核心线程:必须大于0,一直存在的线程,不会被关闭
- 最大线程:一般设置大于或者等于核心线程,不能小于核心线程,最大线程数=核心线程数+普通线程数,普通线程数在等待时间满后会自动关闭,节省开销
- 处理时间:每个线程处理任务的最大时间,普通线程超过该时间会shutDown
- 时间单位:处理时间的单位,一般设置为秒
- 阻塞队列:选择缓存队列的方式,未处理的任务会在阻塞队列里面等待线程执行
- 线程:使用线程工程创建线程,可以命名,方便运行区分线程属于哪个线程池的
- 拒绝策略:当阻塞队列满了,无法继续添加任务且工作线程等于最大线程时执行拒绝策略,有4种方式,推荐使用CallerRunsPolicy,当队列满时,添加进来的任务会重新调度给main线程进行处理,也就是不在线程池中创建的线程执行,此时任务不属于异步实现,相当于运行了线程的run方法,而不是start.
二.核心参数设置
//在 Java 中,通过 Runtime 类可以获取与系统运行时环境相关的信息和进程控制功能。其中的 getRuntime() 方法可以返回当前程序正在运行的 Java 虚拟机(JVM)的运行时实例。通过这个实例,我们可以调用 availableProcessors() 方法来获取当前系统中可用的处理器数量。
//核数
int processorAmount = Runtime.getRuntime().availableProcessors();
1.核心线程: 推荐使用以下方式设置核心线程,根据系统可用的核心处理器数量*2 +1
(CPU密集:核心线程数=CPU内核数 + 1)
(IO密集: 核心线程数=CPU内核数 * 2)
int coreThreadSize = processorAmount * 2 + 1;
2.最大线程数:推荐核心线程数+核心线程数/2
int maxThreadSize = coreThreadSize + (coreThreadSize / 2);
3.阻塞队列:常用有界队列,ArrayBlockingQueue,需要设置队列大小
4.拒绝策略:
a. 处理日志无关紧要,稍微缺失一些不影响业务的使用:DiscardPolicy
b. 处理实时性且效率高的,不容新提交的任务不被执行,使用:AbortPolicy(默认策略),任务队列满,无法提交新的任务时,会抛出异常:RejectedExecutionException 拒绝任务提交
c. 当队列满无法提交新的任务时,允许新的任务在提交任务的线程中执行,即提交者线程执行,可以使用:CallerRunsPolicy策略,任务必须被执行,可能会影响一些效率
d. 当队列已经满了,无法提交新的任务且可以将最新提交的任务抛弃,然后将任务放入队列,可以使用:DiscardOldestPolicy
选择合适的拒绝策略要根据具体的业务需求来决定。例如,当对任务处理实时性要求很高时可以选择 AbortPolicy,当需要提交者参与任务执行时可以选择 CallerRunsPolicy,当可以接受任务丢失时可以选择 DiscardPolicy,而当希望保留最新提交的任务时可以选择 DiscardOldestPolicy。
三.创建线程池
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Configuration
@EnableAsync
public class CommitExecutor {
//最大的缓存任务数
private static final int MAXIMUM_CACHED_AMOUNT = 20000;
//核数
int processorAmount = Runtime.getRuntime().availableProcessors();
//核心线程数量
int coreThreadSize = processorAmount * 2 + 1;
//最大线程数量
int maxThreadSize = coreThreadSize + (coreThreadSize / 2);
// ThreadPoolExecutor executor=new ThreadPoolExecutor(
// coreThreadSize,
// maxThreadSize,
// 60,
// TimeUnit.SECONDS,
// new ArrayBlockingQueue<>(MAXIMUM_CACHED_AMOUNT),
// new ThreadFactory() {
// @Override
// public Thread newThread(@NotNull Runnable r) {
// return new Thread(r);
// }
// },
// new ThreadPoolExecutor.CallerRunsPolicy()
// );
//
//
// public void execute(Runnable task) {
// executor.execute(task);
// }
@Bean(Constant.SYNC_EXECUTOR)
public Executor syncExecutor(){
return new ThreadPoolExecutor(
coreThreadSize,
maxThreadSize,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(MAXIMUM_CACHED_AMOUNT),
new ThreadFactory() {
@Override
public Thread newThread(@NotNull Runnable r) {
return new Thread(r,Constant.SYNC_EXECUTOR);
}
},
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
}