线程池(重点)
重点:三大方法、七大参数、四种拒绝策略
池化技术
概述:
- 程序运行的本质:占用系统的资源
- 优化资源的使用:池化技术
- 常用的池化技术:线程池、连接池、内存池、对象池等
- 池化技术:提前准备好一些资源(资源的开闭消耗资源),有需要的时候,在池中取,用完之后放回池中中。
线程池的好处
- 降低资源的消耗
- 提高响应叔叔
- 方便管理
线程复用、可以控制最大并发数、管理线程
线程池的使用:三个方法
主要线程池使用的传统的区别
注意:阿里巴巴开发手册规定线程池不能使用Executors创建、而是通过ThreadPoolExecutor的方式
public class PoolTest {
/**
* Executors 工具类:三大方法
* @param args
*/
public static void main(String[] args) {
// 单线程池
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
// 固定线程池
ExecutorService executorService2 = Executors.newFixedThreadPool(3);
// 缓存池: 不固定线程的大小,需要多少线程就自动根据需求创建多少线程
ExecutorService executorService3 = Executors.newCachedThreadPool();
try {
for (int i = 0; i < 10; i++) {
// 未使用线程池时,创建线程的方式
//new Thread().start();
// 使用池化技术进行线程创建
executorService2.execute(()->{
System.out.println(Thread.currentThread().getName());
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 注意:资源最后要关闭
executorService2.shutdown();
}
}
}
- 单线程
- 固定线程池
- 缓存线程池
七大参数
- 源码分析
// newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
// newFixedThreadPool(3);
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
// newCachedThreadPool();
public static ExecutorService newCachedThreadPool() {
// 最大核心数是Interge.MAX_VALUE,利用这个创建可以回造成OOM
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- 上面的代码可以看出:开启线程池代码的本质是ThreadPoolExecutor:里面的就是七大参数
public ThreadPoolExecutor(int corePoolSize,// 核心线程池大小
int maximumPoolSize, // 最大核心线程池大小
long keepAliveTime, // 超时了没有人调用就会释放
TimeUnit unit,// 超时单位
BlockingQueue<Runnable> workQueue,// 阻塞队列
ThreadFactory threadFactory,// 线程工厂,创建线程的,一般不用动
RejectedExecutionHandler handler// 拒绝策略) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
- 七大参数
int corePoolSize,// 核心线程池大小
int maximumPoolSize, // 最大核心线程池大小
long keepAliveTime, // 超时了没有人调用就会释放
TimeUnit unit,// 超时单位
BlockingQueue<Runnable> workQueue,// 阻塞队列
ThreadFactory threadFactory,// 线程工厂,创建线程的,一般不用动
RejectedExecutionHandler handler// 拒绝策略)
- 银行排队案例理解线程池
最上面是服务区
最下面是等待区:等待区被称为阻塞队列
当等待区未满时,服务区不是全开,只开启最左边两个窗口(被称为核心线程池大小),当服务区全开的时候,被称为最大核心池大小。当服务和和等待都满了的时候,进来排队的人,如何组织他们称为拒绝策略,如果窗口长时间没有被使用,则会超时释放
自定义线程池
// 自定义创建线程池,利用工具类不安全,实际生产都是使用这个
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,
Runtime.getRuntime().availableProcessors(),
3,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
// 总共有四种拒绝策略
new ThreadPoolExecutor.AbortPolicy()
);
最大线程怎么定义
用于调优
- CPU密集型,几核就定义几,可以保持CPU的效率最高
通过代码获取核数:Runtime.getRuntime().availableProcessors(), - IO密集型,判断程序中十分耗IO的线程,大于这个数就行