文章目录
参考蚂蚁课堂
1.什么是线程池
线程池和数据库连接池类似,可以统一管理维护线程,减少没有必要的开销,就是说你在需要启动线程的时候没有必要自己创建了,只需要从线程池拿就行了,如果用完了还回去就行了没必要创建一个新的,比如说我需要100个线程,我如果说直接创建100个线程一个任务占用一份,用完就扔跟方便筷子似的那就太浪费了。我可以创建一个线程池里面只有10个线程,然后用完了还回来,下一个任务来了接着用,那这样的话我就开10个线程就行了。至于说谁先用,怎么用可以通过线程池去维护。
2.为什么使用线程池
首先我们来看一下线程的生命周期
线程需要经历创建,销毁,中间的CPU调度,阻塞,如果我需要100个线程,那么我如果开100个线程就需要经历100次创建,100次销毁,以及中间不计其数的CPU调度这个开销非常大,效率也很低。但是假如说我一开始就创建好了100个线程都让他处于运行状态,然后直接执行run方法,省去中间大量的创建,调度的过程。所以线程池的核心思想是复用机制,提前创建好一些固定的线程数一直在运行状态实现复用,从而可以减少就绪到运行状态的切换。
3.线程的作用
- 降低资源消耗:通过池化技术重复利用已创建的线程,降低线程创建和销毁造成的损耗。
- 提高响应速度:任务到达时,无需等待线程创建即可立即执行。
- 提高线程的可管理性:线程时稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会因为线程的不合理分布导致资源调度失衡,降低系统的稳定性。使用线程池可以进行统一的分配、调优和监控。
- 提供更多更强大的功能:线程池具备可扩展性,允许开发人员向其中增加更多的功能,比如延时定时线程池,ScheduledThreadPoolExecutor,就允许任务延期执行或定期执行。
4.如何创建线程池
Executors new CachedThreadPool():可缓存线程池
Executors new FixedTheadPool():可定长度
Executors new ScheduledThreadPool():可定时
Executors new SingleTheadExecutor():单例
底层都是基于ThreadPoolExecutor构造函数封装
5.线程池底层是如何实现复用的
首先我先创建好固定的线程一直在运行状态,这个就相当于我们创建一个线程run方法里面写一个死循环,他就一直在运行状态了。然后提交的任务线程会缓存到一个并发队列集合中,交给我们正在运行的线程执行,正在运行的线程就从队列中获取该任务执行。当队列满了就执行拒绝策略。
6.手写一个简易线程池
手写一个线程池需要首先创建一个任务队列,存放各种任务,然后需要规定线程池中线程的个数,以及要执行的任务数。首先我们要创建一个工作线程的类,为了保证这些线程能够一直运行,我们要在里面写一个死循环while的两个条件一个他是否运行我们默认为true,当所有任务执行完我们可以手动改为false,然后就是任务队列的大小。如果任务队列里面有任务就把他取出来,执行run方法,如果没有就是死循环。
private class workThread extends Thread {
@Override
public void run() {
while (isRun || threadJobQueue.size() > 0) {
Runnable command = threadJobQueue.poll();
if(command != null){
command.run();
}
}
}
}
然后构造函数里面要规定最大线程数,以及这个任务数。
public WJZExecutors(int maxThreadCount,int jobCount) {
this.maxThreadCount = maxThreadCount;
threadJobQueue = new LinkedBlockingDeque<Runnable>(jobCount);
for (int i = 0; i < maxThreadCount; i++) {
new workThread().start();
}
}