学习整理总结

本文深入探讨了Java线程池的常见类型,如FixedThreadPool、SingleThreadExecutor、ScheduledThreadPool和CachedThreadPool,详细解释了线程池的核心参数,包括核心线程数、最大线程数、线程空闲超时时间等,并介绍了任务队列和拒绝策略。此外,还讨论了线程池的优缺点和在实际应用中的选择策略,以及Executor和Executors的区别。总结了线程池在任务调度和资源管理上的重要作用,为Java开发者提供了实用的参考资料。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

前言

一、线程池

1.常见的线程池有哪些?

2.线程池有哪些参数?

3.核心线程数和最大线程数有什么区别?

4.线程数超过最大线程数会怎么样?

5.任务队列有哪些?

6.拒绝策略有哪些?

总结







前言

本文章是在学习过程中的问答整理与总结,不定时更新,仅供参考。







一、线程池

1.常见的线程池有哪些?

1.FixedThreadPool(固定容量线程池)

特点:核心线程数等于最大线程数,即该线程池只能创建核心线程。KeepAliveTime为0,线程执行完后立即回收。任务队列为LinkedBlockingQueue。

2.SingleThreadExecutor(单线程线程池)

特点:只有一个核心线程,线程执行完任务直接回收。任务队列为LinkedBlockingQueue。

3.ScheduledThreadPool(定时线程池)

特点:指定核心线程数,普通线程数量无限,线程执行完任务立即回收,任务队列为延时阻塞队列,适合执行定时或周期性的任务。

4.CachedThreadPool(缓存线程池)

特点:没有核心线程,线程闲置60s后回收,任务队列使用SynchronousQueue这种无容量的同步队列,适用于任务量大,但耗时低的场景。

2.线程池有哪些参数?

1.corePoolSize 核心线程数

池中一直保持存活的线程数,即使这些线程处于空闲。但是将 allowCoreThreadTimeOut 设置成true 后,核心线程处于空闲一段时间以上,也会被回收。

2.maximumPoolSize 最大线程数

当核心线程全部繁忙,且任务队列全部打满之后,线程池会临时追加线程,直到总线程数达到maximumPoolSize 这个上限

3.keepAliveTime 线程空闲超时时间

当非核心线程处于空闲状态的时间超过这个时间后,该线程将被回收。当allowCoreThreadTimeOut被设置成true之后,核心线程也会被回收。

4.unit 单位

keepAliveTime 的单位。天、时、分、秒、毫秒、微秒、纳秒

5.workQueue 任务队列

采用阻塞队列实现,当核心线程全部繁忙之后,后续由execute方法提交的Runnable将存放在任务队列中,等待被线程处理。

6.threadFactory 线程工厂

指定线程池创建线程的方式。

7.handler 拒绝策略

当线程池中的线程数达到 maxiMumPoolSize,且workQueue全部打满之后,后续提交的任务将被拒绝,handler可以指定用什么方法拒绝。

3.核心线程数和最大线程数有什么区别?

当线程池接收到一个任务时,首先会判断核心线程数是否已满,如果未满,则会创建一个线程去执行该任务,如果已满,则会判断任务队列是否已满,如果未满,则会将任务添加到队列中,如果已满,则会判断最大线程数是否已满,如果未满,则会创建一个普通线程去执行该任务,如果已满,则会采用拒绝策略拒绝该任务

4.任务队列有哪些?

1.SynchronousQueue 同步队列

这是一个内部没有任何容量的阻塞队列,任何一次的插入操作的元素都需要等待相对的删除/读取操作,否则进行插入操作的线程就要一直等待。

2.LinkedBlockingQueue 无界队列

基于链表结构,使用无界队列后,当核心线程繁忙时,后续任务可以无限地加入队列,因此,线程池中的线程数不会超过核心线程数。这种队列可以提高线程池的吞吐量,但代价是牺牲内存空间,甚至导致内存溢出,另外可以为它指定容量,这样它就变成一个有界队列了。

3.ArrayBlockingQueue 有界队列

基于数组结构,在线程池初始化时,指定队列的容量,后续无法再调整,这样可以有效防止资源耗尽,但可能更难调整和控制。

4.PriorityBlockingQueue 支持优先级排序的无界阻塞队列

存放在PriorityBlockingQueue中的元素必须实现Comparable接口,这样才能通过compareTo() 方法进行排序,优先级最高的元素始终排在列头,但不保证优先级一样的元素的排序,也不保证除优先级最高外的元素,始终处于正确的位置。

5.DelayQueue 延迟队列

基于二叉堆实现,同时具备:无界队列、阻塞队列、优先队列的特点,存放的对象必须实现Delayed接口,通过执行时延从队列中提取任务,时间没到任务取不出。

6.LinkedBlockingDeque 双端队列

既可以从尾部插入/取出元素,也可以从头部插入/取出元素。

7.LinkedTransferQueue 由链表结构组成的无界阻塞队列

采用预占模式,消费者线程取元素时,如果队列不为空,直接取走元素,如果队列为空,就插入一个元素为null的节点,然后消费者线程被等待在这个线程上,后面生产者线程入队时,发现有一个为null的节点,就直接将元素填充到该节点,并唤醒在该节点等待的消费者线程,取走元素。

5.拒绝策略有哪些?

1.AbortPolicy(默认)

丢弃任务并抛出 RejectedExecutionException 异常

2.CallerRunsPolicy

直接运行这个任务的run方法,但并非是由线程池的线程运行,而是交由任务的调用线程处理。

3.DiscardPolicy

直接丢弃任务,不抛出异常

4.DiscardOldestPolicy

将处于等待队列列头的等待任务强行取出,然后再尝试将被拒绝的任务提交到线程池执行

6.Executor和Executors有什么区别

Executor 接口对象能执行我们的线程任务。

Executors 工具类的不同方法能按我们的需求创建不同的线程池,来满足业务需求。

ExecutorService 接口继承了Executor接口,并进行了扩展,提供了更多的方法,我们能够获得任务执行的状态,并可以获取任务的返回值。

使用ThreadPoolExecutor 可以创建自定义线程池。

Future 表示异步计算的结果,他提供了检查计算是否完成的方法,以等待计算的完成,并可以使用get()方法获取计算的结果。

7.什么是Executors框架

Executors 框架是一个可以根据一组执行策略调用、调度、执行和控制的异步任务框架。

无限制地创建线程会引起应用程序内存溢出,所以创建一个线程池是个更好地解决方案,因为可以限制线程的数量,并且可以回收再利用这些线程。利用Executors 框架可以非常方便地创建一个线程池。

8.什么是线程组,为什么不推荐在java中使用

线程组和线程池是两个不同的概念,线程组是为了方便线程的管理,而线程池是为了管理线程的生命周期,复用线程,减少创建销毁线程的开销。

9.为什么使用Executors框架,比使用应用创建和管理线程好

1.使用new Thread() 创建线程比较消耗性能,且创建的线程缺乏管理。

2.无限制地创建线程,线程之间的相互竞争会导致过多占用系统资源导致系统瘫痪。

3.线程之间的频繁交替也会消耗很多资源。

4.直接使用new Thread() 启动的线程不利于扩展,比如:定时执行、定期执行、定时定期执行、线程中断等都不易于实现。

使用Executors框架则具有以下优点

1.复用已存在且空闲的线程从而减少线程对象的创建与销毁造成的开销

2.可有效控制最大并发线程数,提高系统资源的利用率,同时避免过多资源竞争

3.框架中有线程的定时、定期、单线程、并发数控制等功能

10.什么是线程池,为什么要用它

创建线程需要花费昂贵的资源和时间,如果任务来了才创建线程,那么响应时间会变长,而且一个进程能创建的线程数量有限。为避免这些问题,在程序启动时就创建若干线程来响应处理,他们被成为线程池,里面的线程叫做工作线程。从jdk1.5开始,Java API 提供了Executor框架让你可以创建不同的线程池。

11.java线程池中submit()和execute()方法有什么区别

两种方法都可以向线程池提交任务,execute() 方法的返回类型是 void(),它定义在 Executor 接口中。而 submit() 方法可以持有计算结果的Future对象,它定义在 ExecutorService 接口中,它扩展了 Executor 接口,其他线程池类像 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 都有这些方法。

12.线程池的大小如何设置

任务为cpu密集型任务时,线程池大小设置为N+1,N为CPU核心数,比核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其他原因导致任务暂停带来的影响。一旦任务暂停,CPU就会处于空闲状态,多出来的一个线程就可以充分利用CPU的空闲时间。

任务为I/O密集型任务时,线程池大小设置为2N,这种任务应用起来,系统会用大部分时间来处理I/O交互,而线程在处理I/O交互时,不会占用CPU资源,这时就可以将CPU交出给其他线程使用,因此我们可以多配置一些线程。

13.给用户发消息任务超出队列,用哪个拒绝策略,有其他的方法吗

会使用CallerRunsPolicy,还可以使用无界队列,继续添加任务到阻塞队列中等待;或者用消息队列存任务数据,等待线程池慢慢处理。

总结

本文所写内容由翻阅整理所得,不定时更新,仅供参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值