项目代码可到我的git下载,对您有帮助的话麻烦点个星星,爱你哦!
ThreadPoolConfig
package com.threadpool.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author HJH
* @Description: 线程池配置类
* @date 2019/8/1 13:44
* tasks :每秒的任务数
* taskcost:每个任务花费时间,假设为0.1s
* responsetime:系统允许容忍的最大响应时间,假设为1s
*/
@Configuration
@EnableAsync
public class ThreadPoolConfig {
/**
* 每秒需要多少个线程处理?
* tasks/(1/taskcost)
*/
private int corePoolSize = 3;
/**
* 线程池维护线程的最大数量
* (max(tasks)- queueCapacity)/(1/taskcost)
*/
private int maxPoolSize = 3;
/**
* 缓存队列
* (coreSizePool/taskcost)*responsetime
*/
private int queueCapacity = 10;
/**
* 允许的空闲时间
* 默认为60
*/
private int keepAlive = 100;
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(corePoolSize);
// 设置最大线程数
executor.setMaxPoolSize(maxPoolSize);
// 设置队列容量
executor.setQueueCapacity(queueCapacity);
// 设置允许的空闲时间(秒)
//executor.setKeepAliveSeconds(keepAlive);
// 设置默认线程名称
executor.setThreadNamePrefix("thread-");
// 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
ThreadController
package com.threadpool.demo.controller;
import com.threadpool.demo.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author HJH
* @Description: 线程测试控制器
* @date 2019/8/1 13:45
*/
@RestController
public class ThreadController {
@Autowired
private AsyncService asyncService;
@GetMapping("/thread")
public void thread() {
//调用service层的任务
asyncService.executeAsync();
}
}
AsyncServiceImpl
package com.threadpool.demo.service.impl;
import com.threadpool.demo.service.AsyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
/**
* @author HJH
* @Description: 实现
* @date 2019/8/1 13:48
*/
@Service
public class AsyncServiceImpl implements AsyncService {
private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class);
@Async("taskExecutor")
@Override
public void executeAsync() {
logger.info("start executeAsync");
try {
System.out.println("当前运行的线程名称:" + Thread.currentThread().getName());
} catch (Exception e) {
e.printStackTrace();
}
logger.info("end executeAsync");
}
}
AsyncService
package com.threadpool.demo.service;
/**
* @author HJH
* @Description: 线程测试service
* @date 2019/8/1 13:47
*/
public interface AsyncService {
void executeAsync();
}
一共执行了6次,获取到的线程是有序的。ThreadPoolConfig里的参数我是要在本地跑随便设置的,值设得太大的话会抛异常哦!
corePoolSize=1
queueCapacity=Integer.MAX_VALUE
maxPoolSize=Integer.MAX_VALUE
keepAliveTime=60s
allowCoreThreadTimeout=false
rejectedExecutionHandler=AbortPolicy()
需要根据几个值来决定
tasks :每秒的任务数,假设为500~1000
taskcost:每个任务花费时间,假设为0.1s
responsetime:系统允许容忍的最大响应时间,假设为1s
做几个计算:
1,corePoolSize
= 每秒需要多少个线程处理?
threadcount = tasks/(1/taskcost) =tasks*taskcost = (500~1000)*0.1 = 50~100 个线程。corePoolSize设置应该大于50
根据8020原则,如果80%的每秒任务数小于800,那么corePoolSize设置为80即可
2, queueCapacity
= (coreSizePool
/taskcost
)*responsetime
计算可得 queueCapacity = 80/0.1*1 = 80。意思是队列里的线程可以等待1s,超过了的需要新开线程来执行
切记不能设置为Integer.MAX_VALUE,这样队列会很大,线程数只会保持在corePoolSize大小,当任务陡增时,不能新开线程来执行,响应时间会随之陡增。
3, maxPoolSize
= (max(tasks
)- queueCapacity
)/(1/taskcost
)
计算可得 maxPoolSize = (1000-80)/10 = 92
(最大任务数-队列容量)/每个线程每秒处理能力 = 最大线程数
理解:
1、如果当前线程池的线程数还没有达到核心线程数大小,即 poolSize < corePoolSize ,无论是否有空闲的线程,系统回新增一个线程来处理新提交的任务;
2、如果当前线程池的线程数大于或者等于核心线程数大小,即 poolSize >= corePoolSize,且任务队列未满时,将提交的任务提交到阻塞队列中,等待处理workQueue.offer(command);
3、如果当前线程池的线程数大于或者等于核心线程数大小,即 poolSize >= corePoolSize,且任务队列已满时,分以下两种情况:
3.1、poolSize < maximumPoolSize ,新增线程来处理任务;
3.2、poolSize = maximuxPoolSize ,意味中线程池的处理能力已经达到极限,此时会拒绝增加新的任务,至于如何拒绝,取决于RejectedExecutionHandler
4,rejectedExecutionHandler
:根据具体情况来决定,任务不重要可丢弃,任务重要则要利用一些缓冲机制来处理
5,keepAliveTime
和allowCoreThreadTimeout
采用默认通常能满足
以上都是理想值,实际情况下要根据机器性能来决定。如果在未达到最大线程数的情况机器cpu load已经满了,则需要通过升级硬件和优化代码,降低taskcost来处理。