java如何创建线程池(3种方式)
在生产环境中,我们不用Thread来启动线程任务,都通过线程池的方式来进行启动,我们来看看常用的线程池的使用方式

9c70d276ddee62bd98b6e0dbcb12609.png
1.利用Executors静态工厂类创建线程池(不推荐)
- newSingleThreadExecutor创建“单线程化线程池”
- newFixedThreadPool创建“固定数量的线程池”
- newCachedThreadPool创建“可缓存线程池”
- newScheduledThreadPool创建“可调度线程池”
public class MainDemo {
public static void main(String[] args) {
//ExecutorService executorService = Executors.newSingleThreadExecutor();
//ExecutorService executorService = Executors.newFixedThreadPool(100);
//ExecutorService executorService = Executors.newCachedThreadPool();
//executorService.submit(new TaskRunnable());
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
scheduledExecutorService.submit(new TaskRunnable());
}
2.通过ThreadPoolExecutor标准创建线程池(推荐)
1.先创建线程池管理类
package com.leo.springbootmultithreadbasic.threadpool;
import com.leo.springbootmultithreadbasic.common.CommonConstant;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
public class ThreadPoolManage {
/**
* 线程池的阻塞队列:
* LinkedBlockingQueue、SynchronousQueue、ArrayBlockingQueue、LinkedTransferQueue、PriorityBlockingQueue
*/
private LinkedBlockingQueue<Runnable> linkedBlockingQueue = new LinkedBlockingQueue<>(2);
/**
* Thread factory
*/
private ThreadFactory threadFactory = new MyThreadFactory2("ThreadFactory");
public ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(CommonConstant.CORE_POOL_SIZE,
CommonConstant.MAXIMUM_POOL_SIZE,
CommonConstant.KEEP_ALIVE_TIME,
CommonConstant.TIME_UNIT,
linkedBlockingQueue,
threadFactory);
public void addTask(Runnable task) {
threadPoolExecutor.execute(task);
}
}
2.通过线程池管理执行线程任务
public class MainDemo {
public static void main(String[] args) {
ThreadPoolManage threadPoolManage = new ThreadPoolManage();
threadPoolManage.addTask(new TaskRunnable());
}
}
3.SpringBoot利用ThreadPoolTaskExecutor创建线程池
ThreadPoolTaskExecutor是spring进行封装ThreadPoolExecutor的,其本质是还是ThreadPoolExecutor,在SpringBoot框架中还是更推荐用ThreadPoolTaskExecutor创建线程池
1.由于要添加线程时进行日志的打印,我们先写一个类来继承ThreadPoolTaskExecutor
package com.wwj.component;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
/*
showThreadPoolInfo 方法中将任务总数、已完成数、活跃线程数,队列大小都打印出来了,然后 Override 了父类的
execute、submit 等方法,在里面调用 showThreadPoolInfo 方法,
这样每次有任务被提交到线程池的时候,都会将当前线程池的基本情况打印到日志中;
*/
@Slf4j
public class ThreadPoolTaskExecutorManage extends ThreadPoolTaskExecutor {
private void showThreadPoolInfo() {
ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
if (null == threadPoolExecutor) {
return;
}
log.info("{},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
this.getThreadNamePrefix(),
threadPoolExecutor.getTaskCount(),
threadPoolExecutor.getCompletedTaskCount(),
threadPoolExecutor.getActiveCount(),
threadPoolExecutor.getQueue().size());
}
@Override
public void execute(Runnable task) {
this.showThreadPoolInfo();
super.execute(task);
}
@Override
public void execute(Runnable task, long startTimeout) {
this.showThreadPoolInfo();
super.execute(task, startTimeout);
}
@Override
public Future<?> submit(Runnable task) {
this.showThreadPoolInfo();
return super.submit(task);
}
@Override
public <T> Future<T> submit(Callable<T> task) {
this.showThreadPoolInfo();
return super.submit(task);
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
this.showThreadPoolInfo();
return super.submitListenable(task);
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
this.showThreadPoolInfo();
return super.submitListenable(task);
}
}
2.构建配置类
package com.wwj.config;
import com.wwj.component.ThreadPoolTaskExecutorManage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig {
@Value("${async.executor.thread.core_pool_size}")
private int corePoolSize;
@Value("${async.executor.thread.max_pool_size}")
private int maxPoolSize;
@Value("${async.executor.thread.queue_capacity}")
private int queueCapacity;
@Value("${async.executor.thread.name.prefix}")
private String namePrefix;
@Bean(name = "asyncServiceExecutor")
public Executor asyncServiceExecutor() {
log.info("start asyncServiceExecutor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutorManage();
//配置核心线程数
executor.setCorePoolSize(corePoolSize);
//配置最大线程数
executor.setMaxPoolSize(maxPoolSize);
//配置队列大小
executor.setQueueCapacity(queueCapacity);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix(namePrefix);
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// AbortPolicy:该策略是线程池的默认策略。使用该策略时,如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常。
// DiscardPolicy:这个策略和AbortPolicy的slient版本,如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常。
// DiscardOldestPolicy:这个策略从字面上也很好理解,丢弃最老的。也就是说如果队列满了,会将最早进入队列的任务删掉腾出空间,再尝试加入队列。
//因为队列是队尾进,队头出,所以队头元素是最老的,因此每次都是移除对头元素后再尝试入队。
// CALLER_RUNS:当队列忙了,由主线程去执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
3.编写配置文件
server.port=8080
# 异步线程配置
# 配置核心线程数
async.executor.thread.core_pool_size = 2
# 配置最大线程数
async.executor.thread.max_pool_size = 2
# 配置队列大小
async.executor.thread.queue_capacity = 4
# 配置线程池中的线程的名称前缀
async.executor.thread.name.prefix = async-service-
4.利用注解进行使用
package com.wwj.service.impl;
import com.wwj.service.AsyncService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class AsyncServiceImpl implements AsyncService {
@Override
@Async("asyncServiceExecutor")
public void executeAsync() {
log.info("start executeAsync");
System.out.println("do something");
log.info("end executeAsync");
}
}
直接调用方法即可