目录
线程池
1.线程池和线程的优缺点
线程优点:通过new Thread()创建一个线程,简单便捷
缺点:相比较线程池,没有线程管理者,可能会无限制的创建线程,不仅消耗资源,还 会降低系统的稳定性
线程池的优点
1.降低资源的消耗,通过重复利用已经创建好的线程池可以降低线程创建和销毁带来的资源消耗
2.提供响应速度,当任务完成之后,线程不需要等待线程创建好就可以立即执行任务
3.提供线程的可管理性,使用线程池可以对线程进行统一的分配,监控和调优
2.线程池常用的几种创建方式
public static void main(String[] args) {
//创建一个单核心的线程池
ExecutorService threadPool1 = Executors.newSingleThreadExecutor();
//创建一个定长的线程池,核心线程数是3
ExecutorService threadPool1 = Executors.newFixedThreadPool(3);
//创建一个定长且可以按照计划执行的线程池
ExecutorService threadPool1 = Executors.newScheduledThreadPool(3);
//创建一个线程可自动增加的线程池
ExecutorService threadPool1 = Executors.newCachedThreadPool();
//创建一个具有抢占式的线程池
ExecutorService threadPool1 = Executors.newWorkStealingPool();
for (int i = 0; i < 20; i++) {
当执行execute方法线程才创建
threadPool1.execute(()->{
System.out.println(Thread.currentThread().getName()+"办理业务");
});
}
//用完之后要放回到线程池供其他任务使用
threadPool1.shutdown();
}
实际开发中这5种创建线程池的方式一般不用,都new ThreadPoolExeutor,然后自己传入7个参数,自己设置值,为什么呢?
答:主要还是因为尽可能的规避资源耗尽的风险,因为这些创建好了的线程池,要么就是阻塞队列设置的值是 Integer.MAX_VALUE ,要么就是创建最大线程数的值是 Integer.MAX_VALUE,这样可能会导致任务的堆积,或者可能会创建大量的线程,从而导致OOM
注:什么是OOM?
答:OOM,全称:“Out Of Memory”,中文名叫"内存用完了",来源于java.lang.OutOfMemoryError,当jvm没有足够的内存为对象分配空间且垃圾回收器也满了,就会抛出这个error
上面这5种创建方式,底层其实都是new ThreadPoolExecutor
new ThreadPoolExecutor的7大参数分别代表什么意思?
答:int corePoolSize 常驻核心线程池数量
int maximumPoolSize 最大线程池数量
long keepAliveTime 线程存活时间的值(3L,5L)
TimeUnit unit 线程存活时间的单位(毫秒,秒,分钟)
线程存活时间:除了核心线程外,那些被新创建出来的线程可以存活多久。意味着,这些新的线程一旦完成任务,而后面都是空闲状态时,就会在一定时间后被摧毁。
BlockingQueue<Runnable> workQueue 阻塞队列
阻塞队列:如果常驻线程数量用完了,此时还有请求,那么这个请求就会放到阻塞队列里面进行等待
ThreadFactory threadFactory 线程工厂,用来创建线程
RejectedExecutionHandler defaultHandler 拒绝策略
拒绝策略分4种
1.当线程池中的线程数到达了maximumPoolSize设置的最大值,此时又来了一个任务请求处理,这时候就会 丢弃任务并抛出RejectedExecutionException异常。ThreadPoolExecutor.AbortPolicy
2.当线程池中的线程数到达了maximumPoolSize设置的最大值,此时又来了一个任务请求处理,这时候就会 丢弃任务,但是不会抛出异常ThreadPoolExecutor.DiscardPolicy
3.当线程池中的线程数到达了maximumPoolSize设置的最大值,此时又来了一个任务请求处理,由调用线程(提交任务的线程,谁让这个任务来)处理该任务ThreadPoolExecutor.CallerRunsPolicy
4.当线程池中的线程数到达了maximumPoolSize设置的最大值,且阻塞队列里面也满了,此时又来了一个任务请求处理,丢弃队列最前面的任务,然后重新提交被拒绝的任务,ThreadPoolExecutor.DiscardOldestPolicy
线程池底层执行原理
1.如果当前线程池的线程数目小于 corePoolSize常驻核心线程,则每来一个任务,都会创建新的线程来处理
2.如果当前线程池数目 >=corePoolSize时,则每来一个任务都会放到阻塞队列里面去,如果放成功,则会等待有空间线程的时候将其取出来执行
3.那如果放失败,说明阻塞队列也满了,那么这时候会创建新的线程来处理这个任务,当线程池的线程数量>=maximumPoolSize最大线程数设置的值的时候,会触发拒绝策略,拒绝策略有4种,默认的是抛出异常
自定义线程池
代码演示
/**
*自定义线程池
*/
public class Thead {
public static void main(String[] args) {
//创建一个自定义线程池 new ThreadPoolExecutor 传入7个参数
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2,5,600L,TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory() ,new ThreadPoolExecutor.AbortPolicy());
for (int i = 0; i < 10; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"-办理业务");
});
}
//处理完要将线程放到线程池中处理其他的任务
threadPool.shutdown();
}
}
Springboot整合线程池
1.先写个线程池的config类
@Configuration
//开启多线程
@EnableAsync
public class ThreadPoolConfig {
@Bean("taskExecutor")
public Executor asyncServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(5);
// 设置最大线程数
executor.setMaxPoolSize(20);
// 配置队列大小
executor.setQueueCapacity(3);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(5);
// 设置默认线程名称
executor.setThreadNamePrefix("ThreadPool");
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 执行初始化
executor.initialize();
return executor;
}
}
写完上面的这个config类,只需要在service业务处理层的方法上加一个@Async("taskExecutor")
括号里面写的要和上面config类里面@Bean括号写的要一致
end....