线程池的介绍
线程池
一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。(节选自百度百科)
🔎线程池的参数介绍
这是线程池的几种构造方法
下面将逐一介绍构造方法种的参数,以红框的构造方法为例
🌻参数(int corePoolSize, int maximumPoolSize)
corePoolSize:表示核心线程数
maximumPoolSize:表示最大线程数
举个栗子🥝
将线程池想象成一个公司
公司里有很多的员工,包括 (1)正式员工 (2)实习员工/非正式员工
其中
核心线程数表是正式员工的数量
最大线程数表是正式员工的数量 + 实习员工的数量
🌻参数(int corePoolSize, int maximumPoolSize)
long keepAliveTime:表示保持存活的时间
TimeUnit unit:表示存活时间的单位
注意!
保持存活的时间是实习员工保持存活的时间
举个栗子🥝
公司的正式员工因为签订了劳动合同,所以不能随意的辞退
实习员工因为签订的是实习合同,所以辞退也不会有什么事
当公司业务比较繁忙的时候,就需要多招聘一些实习生来增加生产力
但当业务少了的时候,也不能直接就将实习生辞退
需要观察一下是不是只是最近一两天业务比较少,过后还是比较忙
如果是,就先让实习员工继续实习
如果不是,直接辞退
这就是实习员工保持存活的时间
🌻参数(BlockingQueue workQueue)
表示阻塞队列
线程池要管理很多任务,这些任务是通过阻塞队列进行组织的
🌻参数(ThreadFactory threadFactory)
表示工厂模式
创建线程的辅助的类
🌻参数(RejectedExecutionHandler handler)
表示线程池的拒绝策略
下面介绍线程池的4种拒绝策略
🌼case1(ThreadPoolExecutor.AbortPolicy)
表示如果队列中任务满了,继续添加任务,将会抛出异常
🌼case2(ThreadPoolExecutor.CallerRunsPolicy)
表示添加该任务的线程自己执行该任务
🌼case3(ThreadPoolExecutor.DiscardOldestPolicy)
表示丢弃队列中的最老的任务(队首),去执行添加的任务
🌼case4(ThreadPoolExecutor.DiscardPolicy)
表示丢弃新添加的任务,继续执行队列中的任务
🔎线程池的工作流程
🌻模拟实现线程池
模拟实现一个简单的线程池
//模拟实现线程池
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
class ExThreadPool {
//创建阻塞队列,将所需执行的任务放到队列中
private BlockingQueue<Runnable> queue = new LinkedBlockingDeque<>();
//submit()方法,创建所需执行的任务
public void submit(Runnable runnable) throws InterruptedException{
queue.put(runnable);
}
//创建一个固定线程数为n的线程池
public ExThreadPool(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 Test {
public static void main(String[] args) throws InterruptedException {
ExThreadPool pool = new ExThreadPool(10);
for (int i = 0; i < 1000; i++) {
int num = i;
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello " + num);
}
});
}
}
}
代码描述
创建一个线程数为10的线程池
执行System.out.println("hello " + num); 1000次
🌻线程池的工作流程
1.提交任务
2.判断核心线程数是否达到最大
--------2.1未到达最大值:执行任务
--------2.2达到最大值:判断阻塞队列是否已满
3.阻塞队列时否已满
--------3.1未满:将任务添加到阻塞队列等待线程执行
--------3.2已满:判断线程数是否达到最大值
4.线程数是否达到最大值
--------4.1未达到最大值:创建非核心线程执行任务
--------4.2达到最大值:执行拒绝策略
🔎使用Executors 创建常见的线程池
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(10);
}
newFixedThreadPool(n)
创建固定线程数为n的线程池
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
}
newCachedThreadPool()
创建线程数目动态增长的线程池
public static void main(String[] args) {
ExecutorService pool = Executors.newSingleThreadExecutor();
}
newSingleThreadExecutor()
创建只包含单个线程的线程池
public static void main(String[] args) {
ExecutorService pool = Executors.newScheduledThreadPool(1000);
}
newScheduledThreadPool(n)
设定延迟时间n(单位:毫秒)后执行命令
🔎结尾
创作不易,如果对您有帮助,希望您能点个免费的赞👍
大家有什么不太理解的,可以私信或者评论区留言,一起加油