java线程池原理详解

1 概述

在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源,创建线程亦是如此,这导致在高并发中效率低下并且资源耗费严重,因此,池化资源技术应运而生,所以就有了线程池。

2 Executors类

JDK为我们封装了一套操作多线程的框架Executors,常用的方法如下:

newSingleThreadExecutor:
创建一个单线程的线程池,这个线程池有且只有一个线程在工作
newFixedThreadPool:
创建固定大小的线程池,通过带参数创建指定线程数大小,每提交一个任务就会创建一个新的线程,直到达到指定线程数
newCachedThreadPool:
创建一个可缓存的线程池,如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60 秒不执行任务)的线程
newScheduledThreadPool:
创建一个无限大小的线程池,每提交一个请求创建一个线程,支持定时和周期性任务执行

其实这些方法最终都是创建了ThreadPoolExecutor 对象,只是传入的参数不同

3 线程池的实现原理

在《阿里巴巴java开发规范》中是禁止使用Executors类创建线程池,必须通过合理设定ThreadPoolExecutor对象参数来创建线程池
看ThreadPoolExecutor源码有这几个参数

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {

corePoolSize

核心线程数,当有任务进来的时候,如果当前线程数还未达到 corePoolSize 个数,则创建核心线程,核心线程有几个特点:

  1. 当线程数未达到核心线程最大值的时候,新任务进来,即使有空闲线程,也不会复用,仍然新建核心线程
  2. 核心线程一般不会被销毁,即使是空闲的状态,但是如果通过方法allowCoreThreadTimeOut(boolean value) 设置为 true 时,超时也同样会被销毁
  3. 生产环境首次初始化的时候,可以调用prestartCoreThread() 方法来预先创建所有核心线程,避免第一次调用缓慢

maximumPoolSize

除了有核心线程外,有些策略是当核心线程完全无空闲的时候,还会创建一些临时的线程来处理任务,maximumPoolSize 就是核心线程 + 临时线程的最大上限。临时线程有一个超时机制,超过了设置的空闲时间没有事儿干,就会被销毁。

keepAliveTime

这个就是上面两个参数里所提到的超时时间,也就是线程的最大空闲时间,默认用于非核心线程,通过 allowCoreThreadTimeOut(boolean value) 方法设置后,也会用于核心线程。

unit

这个参数是用来指定keepAliveTime参数的时间单位,秒、分、时等。

workQueue

它是 BlockingQueue类,即阻塞队列。
当核心线程满了并且没有空闲的了,新来的任务就会被放到这个等待队列中。这个参数其实一定程度上决定了线程池的运行策略,为什么这么说呢,因为队列分为有界队列和无界队列。
有界队列: 队列的长度有上限,当核心线程满载的时候,新任务进来进入队列,当达到上限,如果没有核心线程去即时取走处理,这个时候,就会创建临时线程。(警惕临时线程无限增加的风险)
无界队列: 队列没有上限的,当没有核心线程空闲的时候,新来的任务可以无止境的向队列中添加,而永远也不会创建临时线程。(警惕任务队列无限堆积的风险)

threadFactory

它是一个接口,用于实现生成线程的方式、定义线程名格式、是否后台执行等等,可以用 Executors.defaultThreadFactory() 默认的实现即可,也可以使用自定义的线程工厂

handler

当没有空闲的线程处理任务(即核心线程满了,并且都是在运行状态),并且等待队列已满(这里只对有界队列有效),再有新任务进来的话,就要做一些取舍了,而这个参数就是指定取舍策略的,ThreadPoolExecutor类提供了下面四种策略可以选择:
AbortPolicy:直接抛出异常,这是默认策略
DiscardPolicy:直接丢弃任务,但是不抛出异常
DiscardOldestPolicy:丢弃队列最前面的任务,然后将新来的任务加入等待队列
CallerRunsPolicy:由线程池所在的线程处理该任务,比如在 main 函数中创建线程池,如果执行此策略,将有 main 线程来执行该任务

整个线程池的执行过程如下图所示
在这里插入图片描述

(1)用户向线程池提交一个任务,线程池首先判断是否有空闲线程,如果有则使用空闲线程处理任务,
(2)如果没有空闲线程,则判断核心线程数corePoolSize是否满了,没满则创建新的线程处理任务
(3)如果核心线程满了,则判断队列workQueue是否满了,如果没满将任务添加到队列中等待有空闲线程来执行任务
(4)如果队列满了,则判断总容量maximumPoolSize是否满了,如果没满则创建临时线程处理任务,临时线程默认情况下,处于空闲状态时间超过keepAliveTime数则被回收
(5)如果总容量maximumPoolSize满了则执行线程拒绝策略handler

3.1 线程池提交任务

向线程池提交任务的方法有两种,分别是submitexecute
源码如下:
在这里插入图片描述
在这里插入图片描述
从源码可以看出execute方法是提交一个普通的Runnable对象,submit方法既可以提交Runnable对象也可以提交Callable对象,并且具有返回值返回一个Future对象,这个Future对象可以用来判断线程是否执行成功。所以当我们需要判断线程是否执行成功时,可以采用submit方法提交任务,再调用返回的Future对象的get()方法我们最终需要的返回值;如果不关心任务是否执行成功,使用execute方法即可

3.2线程池都有哪些状态

• RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。
• SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。
• STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。
• TIDYING:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()。
• TERMINATED:terminated()方法结束后,线程池的状态就会变成这个。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java线程池是一种用于管理和复用线程的机制,它可以提高多线程程序的性能和效率。在Java中,线程池由ThreadPoolExecutor类实现,通过设置不同的参数可以对线程池的行为进行调整。 以下是Java线程池的一些常用参数及其解释: 1. corePoolSize(核心线程数):线程池中始终保持的活动线程数,即使它们处于空闲状态。当有新任务提交时,如果活动线程数小于corePoolSize,则会创建新线程来处理任务。 2. maximumPoolSize(最大线程数):线程池中允许存在的最大线程数。当活动线程数达到maximumPoolSize并且工作队列已满时,新任务将会被拒绝。 3. keepAliveTime(线程空闲时间):当线程池中的线程数量超过corePoolSize时,多余的空闲线程在等待新任务到来时的最长等待时间。超过这个时间,空闲线程将被终止。 4. unit(时间单位):keepAliveTime的时间单位,可以是秒、毫秒、微秒等。 5. workQueue(工作队列):用于存储等待执行的任务的阻塞队列。常见的工作队列有ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue等。 6. threadFactory(线程工厂):用于创建新线程的工厂类。可以自定义线程的名称、优先级等属性。 7. handler(拒绝策略):当线程池无法接受新任务时的处理策略。常见的拒绝策略有AbortPolicy(默认,抛出RejectedExecutionException异常)、CallerRunsPolicy(由调用线程执行任务)、DiscardPolicy(直接丢弃任务)和DiscardOldestPolicy(丢弃最旧的任务)。 这些参数可以根据实际需求进行调整,以达到最佳的线程池性能和资源利用率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值