线程池原理

本文详细介绍了Java线程池的工作原理,包括创建线程池的多种方式如ThreadPoolExecutor和Executors工厂方法,执行任务的execute和submit方法。核心参数如corePoolSize、maximumPoolSize和workQueue的解析,以及线程池的五种状态转换。此外,还深入探讨了线程复用的实现机制,如何通过线程池提高系统效率并避免资源浪费。
摘要由CSDN通过智能技术生成

序言

有时候在项目中,频繁的创建消耗线程是一种巨大的开销,引入线程池,减少创建消耗线程的开销,让线程得到复用,提升效率。

创建线程池的几种方式
  1. ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue workQueue,
    RejectedExecutionHandler handler)
  2. Executors.newFixedThreadPool(int size)
  3. Executors.newSingleThreadExecutor()
  4. Executors.newCachedThreadPool()
  5. Executors.newScheduledThreadPool()
  6. Executors.newWorkStealingPool()
执行线程池的几种方式
  1. void execute(Runnable command)
  2. Future<?> submit(Runnable task)
线程池的核心参数
  1. corePoolSize 核心参数,当有新任务来时,判断当前池中线程是否大于等于coreSize,如果是小于,那么新建一个线程运行任务,线程池中的核心线程创建后一般不会销毁,会常驻在池中,可以用allowCoreThreadTimeOut方法设置是否对核心线程超时销毁
  2. maximumPoolSize 允许的最大线程数,当一个任务来时,会先和coreSize判断,大于等于coreSize,在和workQueue判断是否已满,如果任务队列满了,在判断是否小于maximumPoolSize数,如果小于,创建新的线程执行,执行完后,当超时时间到,会销毁该线程,如果大于maximumPoolSize,会执行拒绝策略
  3. workQueue 任务队列,有三种:ArrayBlockingQueue(有界队列,底层数组保存,任务来了直接放入其中) LinkedBlockingQueue(无界队列,当然也可以指定大小变成有界队列,任务来了创建node封装任务,在放入队列中) SychronousQueue
  4. handler 当新任务来时,当前线程池线程数大于maximumPoolSize时,会执行相关策略:
    new ThreadPoolExecutor.AbortPolicy() 直接抛出异常
    new ThreadPoolExecutor.CallerRunsPolicy() 在当前调用线程中直接调用任务run方法
    new ThreadPoolExecutor.DiscardOldestPolicy() 抛弃队列中未处理的最老的任务,然后重试
    new ThreadPoolExecutor.DiscardPolicy() 直接丢弃任务
线程池五种状态

RUNNING:接受新任务并处理排队的任务
SHUTDOWN:不接受新任务,但处理已排队的任务
STOP:不接受新任务,不处理排队的任务,中断正在进行中的任务
TIDYING:所有任务已经终止,workerCount为零,转换到状态整理的线程将运行terminated()钩子方法
TERMINATED: TERMINATED()已经完成

状态之间的转换

RUNNING -> SHUTDOWN
(RUNNING or SHUTDOWN) -> STOP
SHUTDOWN -> TIDYING
STOP -> TIDYING
TIDYING -> TERMINATED

线程的复用原理

当调用执行方法如execute时,会通过是否大于coreSize,是否加入队列,是否大于maximumPoolSize,在当coreSize时调用addWork(command, true),true表示是核心线程,如果应该加入队列,会调用workQueue.offer(command),唤醒await的线程通过notEmpty.signal()
如果是创建非核心线程:addWork(command, true)
最终在addWork中会调用start方法启动线程,最终走到ThreadPoolExecutor.Work类的runWorker(Worker w)中,while (task != null || (task = getTask()) != null)中,通过getTask()方法的Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
实现线程的复用

比如:一个核心线程来,到while循环中,第一次是task != null为true,执行完后标记false,调用task = getTask(),如果队列中有线程,并且当前线程数小于核心线程或者allowCoreThreadTimeOut是false的,那么会调用workQueue.take(),在workQueue.take()中,会判断
队列中是否有任务,如果没有notEmpty.await(),如果有弹出一个任务,并唤醒线程执行。如果是前线程数大于核心线程或者allowCoreThreadTimeOut是true,那么会调用workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS),如果队列中有任务,直接弹出一个任务返回执行,
如果没有任务,那么会循环等待直到超时,返回null,这时,走到while (task != null || (task = getTask()) != null),介绍该runWorker方法的调用,这样就关闭了非核心线程

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值