线程池知识点整理

1、 什么是线程池

线程池,就是一个池子,任务提交的到线程池后,线程池会在池子里边找有没有空闲的线程,如果没有,就会进入等待状态,有就会分配一个空闲的线程来接受这个任务,当服务执行完,从新放回到线程池,不需要销毁。在这种模式下,系统大大减少了创建线程个销毁线程的资源开销,而且一个线程可以用来执行多个任务,我们可以根据系统的配置灵活调整线程池的大小,从而更高效的执行任务。

2、 为什么要用线程池

多线程并发开发中,线程的数量较多,且每个线程执行一定的时间后就结束了,下一个线程任务到来还需要重新创建线程,这样线程数量特别庞大的时候,频繁的创建线程和销毁线程需要一定时间而且增加系统的额外开销。基于这样的场景,线程池就出现了,线程池可以做到一个线程的任务处理完可以接受下一个任务,并不需要频繁的创建销毁,这样大大节省了时间和系统的开销。

3、 线程池的作用

  1. 利用线程池管理并复用线程,控制最大并发数等。
  2. 实现任务队列缓存策略和拒绝策略。
  3. 实现某些与实践相关的功能。
  4. 隔离线程环境。比如,交易服务和搜索服务在同一台服务器上,分别开启两个线程池,交易线程的资源消耗明显要大;因此需要配置独立的线程池,将较慢的交易服务和搜索服务隔离开,避免各服务线程相互影响。

4、线程生命周期有哪些状态

在这里插入图片描述

5、 创建线程的方式有哪些

  1. 继承Thread类
  2. 实现Runable接口
  3. 实现Callable接口
  4. 使用线程池创建线程
    在这里插入图片描述

6、 线程池代码要素


(1) Executor接口 ,中含有void execute(Runnable command);方法,用于执行给定的命令。
(2) ExecutorService 接口,一种执行器,它提供管理终止的方法,以及可以产生用于跟踪一个或多个异步任务的进度的未来的方法。包含 Future submit(Callable task)方法。
(3) ThreadPoolExecutor类,可用于自定义线程池。
(4) Executors工厂类,提供了很多实现线程池的方式。

7、 线程池有哪几种

(1)Executors.newWorkStealingPool :jdk1.8新增,创建一个线程池,该线程池维护足够多的线程以支持给定的并行级别,可以使用多个队列减少竞争。次构造方法中把cpu的数量设置为默认的并行度。
(2)Executors.newCachedThreadPool****:是一个会根据需要创建新线程的线程池,无界线程池,核心线程为0,maximumPoolSize为Integer.MAX_VALUE,是高度可伸缩的线程池。keepAliveTime默认60s,如果工作线程处于空闲状态,则回收线程。如果任务数增加,则再次创建新线程处理任务。
使用场景:用于并发执行大量短期的小任务。
(3)Executors. newFixedThreadPool: 创建指定大小的线程池,这个大小既是核心线程大小,也是最大线程数,不存在空闲线程,所以keepAliveTime=0,如果超出大小,放入block队列,即LinkedBlockingQueue队列。有OOM风险。适用于需要保证所有提交的任务都要被执行的情况。
使用场景:FixedThreadPool 适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。
4)Executors. newSingleThreadPool:创建一个单线程的线程池,相当于单线程 穿行执行所有任务,保证按任务的提交顺序依次执行。
使用场景:适用于串行执行任务的场景,一个任务一个任务地执行。
**(5)Executors.newScheduledThreadPool:**线程数最大至Integer.MAX_VALUE,存在OOM风险。他是ScheduledExecutorService接口家族的实现类,支持定时及周期性任务执行。相比Timer,ScheduledExecutorService更安全,功能更强大,与newCachedThreadPool的区别是不回收工作线程。
**使用场景:**周期性执行任务的场景,需要限制线程数量的场景。

8、 线程池都有哪几种工作队列?

ArrayBlockingQueue(有界队列)是一个用数组实现的有界阻塞队列,按FIFO排序量。

LinkedBlockingQueue(可设置容量队列)基于链表结构的阻塞队列,按FIFO排序任务,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQuene;newFixedThreadPool线程池使用了这个队列。

DelayQueue(延迟队列)是一个任务定时周期的延迟执行的队列。根据指定的执行时间从小到大排序,否则根据插入到队列的先后排序。newScheduledThreadPool线程池使用了这个队列。
PriorityBlockingQueue(优先级队列)是具有优先级的无界阻塞队列;

SynchronousQueue(同步队列)一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene,newCachedThreadPool线程池使用了这个队列。

9、 ThreadPoolExecutor参数分析

	public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

在这里插入图片描述
在这里插入图片描述

9、线程池工作原理

线程池工作原理:任务开始后,开始创建新的线程,当达到核心线程数后,新的任务进来不在创建新的线程,这时候把任务加入工作队列,当达到工作队列的长度后,新任务开始创建新的普通线程,直到数量达到线程池的最大核心数量,后面再有新任务则执行饱和策略或拒绝,抛出异常。

10、使用线程池应注意的几点

在这里插入图片描述

11、使用无界队列的线程池会导致内存飙升吗?

会的,newFixedThreadPool使用了无界的阻塞队列LinkedBlockingQueue,如果线程获取一个任务后,任务的执行时间比较长(比如,上面demo设置了10秒),会导致队列的任务越积越多,导致机器内存使用不停飙升, 最终导致OOM。

发布了6 篇原创文章 · 获赞 5 · 访问量 1002

猜你喜欢

转载自blog.csdn.net/qq_28203555/article/details/103712203