线程池
线程池参数
创建线程的api
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
这几个核心参数的作用:
corePoolSize
为线程池的基本大小。maximumPoolSize
为线程池最大线程大小。keepAliveTime
和unit
则是线程空闲后的存活时间。workQueue
用于存放任务的阻塞队列。handler
当队列和最大线程池都满了之后的饱和策略。
线程池定义的状态:
RUNNING
自然是运行状态,指可以接受任务执行队列里的任务SHUTDOWN
指调用了shutdown()
方法,不再接受新任务了,但是队列里的任务得执行完毕。STOP
指调用了shutdownNow()
方法,不再接受新任务,同时抛弃阻塞队列里的所有任务并中断所有正在执行任务。TIDYING
所有任务都执行完毕,在调用shutdown()/shutdownNow()
中都会尝试更新为这个状态。TERMINATED
终止状态,当执行terminated()
后会更新为这个状态。
通常我们都是用: threadPool.execute(new Job())的方式来提交一个任务到线程池中,核心就是execute()函数,其过程是:
- 获取当前线程池的状态。
- 当前线程数量小于 coreSize 时创建一个新的线程运行。
- 如果当前线程处于运行状态,并且写入阻塞队列成功。
- 双重检查,再次获取线程池状态;如果线程池状态变了(非运行状态)就需要从阻塞队列移除任务,并尝试判断线程是否全部执行完毕。同时执行拒绝策略。
- 如果当前线程池为空就新创建一个线程并执行。
- 如果在第三步的判断为非运行状态,尝试新建线程,如果失败则执行拒绝策略
借助<聊聊并发>的一张图来描述这个过程:
SpringBoot使用线程池:
配置参数
@Configuration
@EnableAsync
public class ThreadPoolConfig {
@Bean("threadPool")
public Executor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor=new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(10);//线程池最小线程数
taskExecutor.setMaxPoolSize(50);//线程池最大线程数
taskExecutor.setQueueCapacity(200);//阻塞队列大小
taskExecutor.setKeepAliveSeconds(60);//线程空闲时间
taskExecutor.setThreadNamePrefix("taskThread--");//线程名称前缀
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);//关闭线程时是否等待完成任务
taskExecutor.setAwaitTerminationSeconds(60);//等待进入终止状态时间
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//线程池饱 和拒绝任务策略
return taskExecutor;
}
}
测试使用线程池:
@Component
public class TestService {
@Async("threadPool")
public void test() {
System.out.println("名字:"+Thread.currentThread().getName());
}
}
线程池隔离
根据业务将线程池进行隔离,单独的业务系统使用单独的线程池,通过hystrix来实现
添加hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
定义两个线程池,分别处理订单,用户任务
public class OrderCommand extends HystrixCommand<String> {
private String orderName;
private static final Logger LOG=LoggerFactory.getLogger(OrderCommand.class);
public OrderCommand(String orderName) {
super(Setter.withGroupKey(
//服务分组
HystrixCommandGroupKey.Factory.asKey("OrderGroup"))
//线程分组
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("OrderPool"))
//线程池配置
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(8)
.withMaximumSize(16)
.withKeepAliveTimeMinutes(6000)
.withMaxQueueSize(50)
.withQueueSizeRejectionThreshold(1000))
//线程池隔离
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy(E xecutionIsolationStrategy.THREAD)));
this.orderName=orderName;
}
@Override
protected String run() throws Exception {
LOG.info("orderName=[{}]",orderName);
return "orderName:"+orderName;
}
}
UserCommand
public class UserCommand extends HystrixCommand<String> {
private String userName;
private static final Logger LOG=LoggerFactory.getLogger(UserCommand.class);
public UserCommand(String userName) {
super(Setter.withGroupKey(
//服务分组
HystrixCommandGroupKey.Factory.asKey("UserGroup"))
//线程分组
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("UserPool"))
//线程池配置
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(8)
.withMaximumSize(16)
.withKeepAliveTimeMinutes(6000)
.withMaxQueueSize(50)
.withQueueSizeRejectionThreshold(1000))
//线程池隔离
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationStrategy(E xecutionIsolationStrategy.THREAD)));
this.userName=userName;
}
@Override
protected String run() throws Exception {
LOG.info("userName=[{}]", userName);
TimeUnit.MILLISECONDS.sleep(300);
return "userName:"+userName;
}
}
测试
OrderCommand o1 = new OrderCommand("手机");
OrderCommand o2 = new OrderCommand("电脑");
UserCommand o3 = new UserCommand("张三");
//阻塞方式
String r1 = o1.execute();
String r2 = o2.execute();
String r3 = o3.execute();
//异常非阻塞
// Future<String> f = o3.queue();
// try {
// String r3 = f.get(300,TimeUnit.MILLISECONDS);
// System.out.println(r3);
// } catch (InterruptedException | ExecutionException | TimeoutException e) {
// e.printStackTrace();
// }
结果: