线程池其实就是一种多线程处理形式,处理过程中可以将任务添加到队列中,然在创建线程后自动启动这些任务。
因为频繁的开启线程或者停止线程,线程需要重新从cpu从就绪状态调度到运行状态,需要发送cpu的上下文切换,效率非常低。
线程池是复用机制,提前创建好一些固定的线程数一直在运行状态,实现复用,从而可以减少就绪到运行状态的切换。
1.首先在银行开业的时候就只会开启2个窗口,并且什么时候也不会关闭-核心线程数
2.当人数大于2并且小于5就让多出来的去等候厅等待-阻塞队列
3.ok,现在来的人数大于5并且小于8了,此时正在休息的3个窗口就打开了,于是乎就一共有了5个窗口 -最大线程数
4.当人数实在是太多了,这次一下来了10个人,咱们窗口以及等候厅都无法放下就会执行拒绝策略!
5.好了现在人数少了,另外3个空闲窗口也没有生意了,为了节约成本呢就关闭了 -超时等待
1.首先,咱们使用异步调用线程池的方式来实现 线程池发送短信;
@enableasync:EnableAsync注解的意思是可以异步执行,就是开启多线程的意思。 可以标注在方法、类上。
@Async:Async的注解放在方发是异步调用方法;放在类上是表示这个类中所有方法都是异步方法。
2.
(1)咱们创建一个ThreadPoolTaskExecutor的子类来打印信息
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;
/**
* @author 苏海龙
* @version 1.0
* @description: TODO
* @date 2023/2/22 8:45
*/
@Slf4j
public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
private void showThreadPoolInfo(String prefix) {
ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
if (null == threadPoolExecutor) {
return;
}
log.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
this.getThreadNamePrefix(),
prefix,
threadPoolExecutor.getTaskCount(),
threadPoolExecutor.getCompletedTaskCount(),
threadPoolExecutor.getActiveCount(),
threadPoolExecutor.getQueue().size());
}
@Override
public void execute(Runnable task) {
showThreadPoolInfo("1. do execute");
super.execute(task);
}
@Override
public void execute(Runnable task, long startTimeout) {
showThreadPoolInfo("2. do execute");
super.execute(task, startTimeout);
}
@Override
public Future<?> submit(Runnable task) {
showThreadPoolInfo("1. do submit");
return super.submit(task);
}
@Override
public <T> Future<T> submit(Callable<T> task) {
showThreadPoolInfo("2. do submit");
return super.submit(task);
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
showThreadPoolInfo("1. do submitListenable");
return super.submitListenable(task);
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
showThreadPoolInfo("2. do submitListenable");
return super.submitListenable(task);
}
}
(2)咱们创建一个线程池配置类来异步调用
import lombok.extern.slf4j.Slf4j;
import org.mybatis.logging.Logger;
import org.mybatis.logging.LoggerFactory;
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.sql.Time;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @author 苏海龙
* @version 1.0
* @description: TODO
* @date 2023/2/22 8:14
*/
@Configuration
@Slf4j
//告诉他这是 线程池异步调用
@EnableAsync
public class ExecutorConfig {
@Bean(name = "asyncServiceExecutor")
public Executor asyncServiceExecutor() {
log.info("start asyncServiceExecutor");
//new出一个咱们上面创建好的ThreadPoolTaskExecutor的子类对象
VisiableThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(10);
//配置最大线程数
executor.setMaxPoolSize(20);
//配置队列大小
executor.setQueueCapacity(100);
//设置超时等待
// executor.setKeepAliveSeconds(100);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("async-service-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
(3)咱们写个实现方法来发送短信并且使用@Async来异步调用咱们创建好的 线程池配置类。
@Override
@Async("asyncServiceExecutor")
public String shendmoblie(PhoneVo phoneVo) {
log.info("start executeAsync");
System.out.println("异步线程要做的事情");
System.out.println("可以在这里执行批量插入等耗时的事情");
//生成随机4位数
String s = RandomUtil.randomNumbers(4);
//发送短信
DuanxinUtils.sendDuanxin(phoneVo.getPhone(),s);
log.info("end executeAsync");
return "发送成功了";
}
注意@Async注解里面的值要和咱们bean注入的值一样
(4)使用jmeter来进行测试:
(5)查看结果:
总结:当前已经提交了47个任务,完成了40个,当前有7个线程在处理任务,还剩0个任务在队列中等待,线程池的基本情况一路了然;