根据开发规范不太建议我们自己去创建线程,毕竟创建与销毁都是一种损耗。
JDK也提供了几种默认的线程池,这些要么就是最大线程数基本没上限,要么就是阻塞队列没有上限,如果代码有问题很容易造成OOM。所以我们来自己实现一个线程池。
springboot集成线程池(超简单四步即成)
- 定义一个线程池:线程池的7大参数可以参考我的上一篇博客。这里我自定义了一个线程工厂类,来制定一个有意义的线程名称,方便出错时回溯。
@Configuration
public class ExecutorServiceConfig {
private Integer corePoolSize = 8;
private Integer maximumPoolSize = 80;
private Long keepAliveTime = 1L;
@Bean
public Executor executorService() {
int cpuNums = Runtime.getRuntime().availableProcessors();
if (cpuNums > corePoolSize) {
maximumPoolSize = cpuNums;
}
return new ThreadPoolExecutor(corePoolSize,
(int) (maximumPoolSize / (1 - 0.9)),
keepAliveTime,
TimeUnit.SECONDS, new SynchronousQueue<>(),
new UserThreadFactory("osCreatePool"),
new ThreadPoolExecutor.AbortPolicy());
}
}
- 自定义线程工厂类:更改了一下线程池的名称
public class UserThreadFactory implements ThreadFactory {
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
UserThreadFactory(String poolName) {
namePrefix = "This thread is from UserThreadFactory's " + poolName + "-thread-";
}
@Override
public Thread newThread(Runnable task) {
Thread t = new Thread(null, task,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
- 定义异步执行接口
@Service
public class AsyncTestServiceImpl implements AsyncTestService {
@Override
@Async("executorService")
public void doTest() {
System.out.println(Thread.currentThread().getName() + "执行了");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "结束执行了");
}
}
- 开启异步支持:@EnableAsync在启动类或者配置类上均可
注意事项(常见异步变同步的原因)
- 在同一个类下的方法中调用其另一个异步方法,异步会变成同步。因为异步注解@Async本质就是spring通过AOP对方法的增强。被增强的时候使用的是动态代理对象去调用方法。如果在同一个类中方法互调属于内部this调用,不会有增强的效果。失去异步的效果,如果有这种需求,自行使用其动态代理对象去调用。
- 由于线程池的扩容发生在corepoolsize与阻塞队列都满了的情况下才会扩容到max。如果我们阻塞队列的值给的很大,corepoolsize的初始值给的很小比如1。这样异步任务都进入到阻塞队列中,并不会开多个线程去执行,失去异步效果。