程序的运行,本质:占用系统的资源,优化资源的使用 =>池化技术
线程池、连接池、内存池、对象池… 创建和销毁十分浪费资源
池化技术:事先准备好一些资源,有人要用就来这里拿,用完了在还回来
线程池的好处: 线程复用、可以控制最大并发数、管理线程
降低资源的消耗提高响应的效率方便管理
三大方法、七大参数、四种拒绝策略
三大方法
Executors.newSingleThreadExecutor(); //单个线程的线程池
Executors.newFixedThreadPool(5); //给定大小的线程池
Executors.newCachedThreadPool(); //无限大小的线程池
public class 三大方法 {
//使用了线程池之后,使用线程池来创建线程
public static void main(String[] args) {
ExecutorService executorService = null;
Executors.newSingleThreadExecutor();//单个线程的线程池
Executors.newFixedThreadPool(5); //给定大小的线程池
Executors.newCachedThreadPool(); //无限大小的线程池
for (int i = 1; i <= 10; i++) {
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+"执行");
});
}
}
}
executorService = Executors.newSingleThreadExecutor();//单个线程的线程池
执行结果:
pool-1-thread-1执行 pool-1-thread-1执行 pool-1-thread-1执行 pool-1-thread-1执行 pool-1-thread-1执行 pool-1-thread-1执行 pool-1-thread-1执行 pool-1-thread-1执行 pool-1-thread-1执行 pool-1-thread-1执行
从结果可以看出: Executors.newSingleThreadExecutor() 是创建的单个线程
executorService = Executors.newFixedThreadPool(5); //给定大小的线程池
执行结果:
pool-2-thread-1执行 pool-2-thread-1执行 pool-2-thread-1执行 pool-2-thread-1执行 pool-2-thread-1执行 pool-2-thread-1执行 pool-2-thread-2执行 pool-2-thread-3执行 pool-2-thread-4执行 pool-2-thread-5执行
从结果可以看出: Executors.newFixedThreadPool(5) 最大线程数是根据我们自己定的数量来创建
executorService = Executors.newCachedThreadPool(); //无限大小的线程池
执行结果:
pool-3-thread-1执行 pool-3-thread-2执行 pool-3-thread-3执行 pool-3-thread-4执行 pool-3-thread-5执行 pool-3-thread-6执行 pool-3-thread-7执行 pool-3-thread-8执行 pool-3-thread-9执行 pool-3-thread-10执行
从结果可以看出:Executors.newCachedThreadPool() 是根据cpu来决定创建多少个线程的
七大参数
三大方法源码分析:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new linkedBlockingQueue()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new linkedBlockingQueue());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
可以发现,三大方法底层都是new了一个ThreadPoolExecutor
ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize, //核心线程池大小
int maximumPoolSize, //最大核心线程池大小
long keepAliveTime, //超时了没有人调用就会释放
TimeUnit unit, //超时时间单位
BlockingQueue 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;
}
| 参数 | 解释 |
|---|---|
| corePoolSize | 核心线程池大小,可以理解为一般情况下池中维护线程的数量 |
| maximumPoolSize | 最大核心线程池大小,可以理解为线程池中可维护的可执行的最大线程数量 |
| keepAliveTime | 超时时间,可以理解为超出了核心线程池大小的线程,在超时时间内没有被使用,超出超时时间后就会被释放掉 |
| TimeUnit | 超时时间单位 |
| BlockingQueue | 阻塞队列,举例说明:核心线程池大小是2个,当请求线程有5个时,超出核心线程池大小的3个会进入到BlockingQueue阻塞队列中等待,设置阻塞队列的容量,如果在阻塞队列中等待的请求超过了阻塞队列的容量,那么就会在线程数最大承载量的范围内创建新的线程 |
| ThreadFactory | 线程工厂,创建线程的 |
| RejectedExecutionHandler | 拒绝策略,当线程请求超过了线程数最大承载(最大核心线程池大小+阻塞队列容量),超出部分执行拒绝策略 |
ThreadPoolExecutor.AbortPolicy():默认的拒绝策略,超出线程数最大承载量的请求会被驳回并抛出异常ThreadPoolExecutor.CallerRunsPolicy():哪来的去哪,超出部分谁发起的请求,谁执行ThreadPoolExecutor.DiscardPolicy():超出了会丢掉任务,但不会抛出异常ThreadPoolExecutor.DiscardOldestPolicy():尝试和最早的线程竞争,如果没竞争过则会被丢弃,不会抛出异常 手动创建线程池
//创建了一个核心线程大小为2,最大核心线程大小为5,超时时间为3秒,阻塞队列容量为3,使用默认线程工厂和默认拒绝策略的线程池
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
最大核心线程池大小到底该如何定义?
CPU密集型:电脑是几核的就可以设置多大,cpu的核数可以通过代码获取Runtime.getRuntime().availableProcessors(),可以在创建线程池的时候直接通过该命令设置最大核心线程池大IO密集型:判断程序中有多少十分耗IO的线程,一般会设置这个数量的两倍



