🐬一.什么是线程池
对于池的概念,我们已经不是第一次接触了,在前面我们了解过常量池,连接池.在这里也可以把线程池也这样理解.线程池就是存放线程的池,方便我们随用随调.
但是官方的解释肯定不是这样的.
线程池: 是一种多线程处理形式,处理过程中把任务添加到队列中,然后在创建线程后自动启动这些任务.
线程池的作用: 降低资源消耗,提高响应速度,方便管理,增加线程的复用.
二.线程池的创建
创建线程我们是使用Executors创建的,它在本质上是ThreadPoolExecutor类的一个封装,Executor的返回值是一个ExecutorService.
下面我们就为大家介绍利用Executors创建线程池的四种方式:
- Executors.newFixedThreadPool:创建固定线程数的线程池
public static void main(String[] args) {
//创建一个有十个线程的线程池
ExecutorService pool= Executors.newFixedThreadPool(10);
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
});
}
- newCachedThreadPool:创建线程数目动态增长的线程池
ExecutorService pool1=Executors.newCachedThreadPool();
- newSingleThreadPool:创建只包含单个线程的线程池
ExecutorService pool2=Executors.newSingleThreadExecutor();
- newScheduledThreadPool:设定延迟时间后执行命令,或者定期执行命令
Executors在本质上是ThreadPoolExecutor类的一个封装,所以我们要去重点了解ThreadPoolExecutor类,它的构造方法的参数
三.ThreadPoolExecut类
我们要去了解一个类,首先要从它的构造方法,我们首先来看看构造方法里面有哪些参数
对于官方文档,给了我们四个构造方法,我们重点要掌握第四个,第四个构造方法涉及到的参数最多.
- corePoolSize :核心线程数
- maximumPoolSize:池中允许最大线程数
- keepAliveTime:临时线程存活的时间
- unit:存活时间的单位
- BlockingQueue<Runnable>workQueue :阻塞队列,用于管理任务
- threadFactory:执行程序创建新线程时使用的工厂
- handler:线程池的拒绝策略,因为达到了线程限制和队列容量
针对这些参数,我们更需要的是重点学习拒绝策略有哪些?
标准库提供的拒绝策略
- ThreadPoolExecutor.AbortPolicy:如果池满了,继续添加任务,直接会抛出抛出一个 RejectedExecutionException 异常
- ThreadPoolExecutor.CallerRunsPolicy:添加的线程自己去执行任务
- ThreadPoolExecutor.DiscardOldestPolicy:丢弃最旧的未处理请求,然后重试 execute .
- ThreadPoolExecutor.DiscardPolicy:丢弃最新的任务.
四.线程池的实现
class MyThreadPool{
//首先定义一个阻塞队列,用来存放任务
private BlockingQueue<Runnable> queue=new LinkedBlockingQueue<>();
//将任务存放到队列中
public void submit(Runnable runnable) throws InterruptedException {
queue.put(runnable);
}
//创建一个固定线程数量的线程池
public MyThreadPool(int n){
for (int i = 0; i < n; i++) {
Thread t=new Thread(()->{
while (true){
try {
Runnable runnable=queue.take();
runnable.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
}
public class ThreadDemo15 {
public static void main(String[] args) throws InterruptedException {
MyThreadPool pool=new MyThreadPool(10);
for(int i=0;i<1000;i++){
int number=i;
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello"+number);
}
});
}
}
}
五.线程池的执行策略
1.向线程池提交任务时,会首先判断线程池中的线程数是否大于设置的核心线程数,如果不大于,就创建一个核心线程来执行任务。
2.如果大于核心线程数,就会判断缓冲队列是否满了,如果没有满,则放入队列,等待线程空闲时执行任务。
3.如果队列已经满了,则判断是否达到了线程池设置的最大线程数,如果没有达到,就创建新线程来执行任务。
4.如果已经达到了最大线程数,则执行指定的拒绝策略此.
线程池的执行策略