如有错误,不妥之处请各位大佬指出 corePoolSize: 线程池中的核心线程数,规定的是线程池中的常驻线程worker 的数量 线程池调度方式 线程池的调度,我主要是指线程池当进入一个新任务时是如何完成整个生命周期的, 新的任务进入 => 也就是说,在核心线程数以及队列容量没有用完之前,设置的最大线程数是无意义的,线程池不会以最大线程数来并行任务。 线程池中的拒绝策略 JDK大佬提供的拒绝策略: 1,注意初始化线程池时确定合理的并行数 在实际的使用以及面试中时常碰到关于线程池的问题,但是线程池作为Java程序开发中的基础组件 拥有相当重要的地位,因此结合源码以及代码实验对线程池进行了探究,并用文字记录下来。
参数
类型
含义
corePoolSize
int
核心线程数
maximumPoolSize
int
最大并行线程数
keepAliveTime
long
非核心线程最大存活时间
unit
TimeUnit
描述存活时间的单位
workQueue
BlockingQueue
存放任务阻塞队列
threadFactory
ThreadFactory
线程工厂
handler
RejectedExecutionHandler
拒绝策略
maximumPoolSize:线程池的线程最大并行数量,规定的是线程池允许的最大的并行线程数量,在核心线程worker 已满 且 队列已满的情况下,会启动非核心的 线程worker 来执行任务
workQueue:核心执行线程已满时用于存放任务的阻塞队列,推荐使用带有边界的ArrayBlockingQueue线程池最基本的运行单元是线程池中的一个内部内,Worker :
ThreadPoolExecutor extends AbstractExecutorService { private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); // java.lang.Integer@Native public static final int SIZE = 32; // 可见 Integer 是4个byte的长度, 使用了3位来标识线程池的状态,其余位数表示线程池 // 当前的worker的数量 private static final int COUNT_BITS = Integer.SIZE - 3; // 线程池允许的最大容量,注意 是理论上可以容纳的最大的worker数量, // 应该没有大佬会 private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 线程池状态标识 private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS; //------------------------------------------------------------ // 获取线程池当前状态 private static int runStateOf(int c) { return c & ~CAPACITY; } // 获取线程池当前 worker 数量 private static int workerCountOf(int c) { return c & CAPACITY; } // 通过位运算获得 线程池状态标识 + 线程池数量的 结果 private static int ctlOf(int rs, int wc) { return rs | wc; } /* 因为继承了 AbstractQueuedSynchronizer,可知: worker 通过 cas的方式实现了线程安全 即 当我在接客的时候 不要往我的房间再塞人 */ Worker extends AbstractQueuedSynchronizer implements Runnable { // worker会从 ThreadFactory中获得一个线程对象 public void run() { // 运行线程 runWorker(this); } // ... 其他方法是 创建线程对象,aqs方式对创建的线程进行运行,阻塞,中断等行为的方法 } final void runWorker(Worker w) { Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null; w.unlock(); // allow interrupts boolean completedAbruptly = true; try { while (task != null || (task = getTask()) != null) { w.lock(); try { // 线程池增强方法,加入线程池的前置操作,线程池监控常用 beforeExecute(wt, task); Throwable thrown = null; try { /** 调用 runable中的run(),执行业务代码块 **/ task.run(); } catch (RuntimeException x) { ... } finally { // 线程池增强方法,完成任务之后的后置操作,线程池监控常用 afterExecute(task, thrown); } } finally { task = null; w.completedTasks++; w.unlock(); } } completedAbruptly = false; } finally { // 记录执行结果,并将Worker移除在执行Set集合 processWorkerExit(w, completedAbruptly); } } }
先查询核心worker数是否已满 ? 未满则新增核心worker执行任务 ,
已满则查看阻塞队列,阻塞队列未满则加入阻塞队列,
已满 且 查看最大并行线程数是否已满,
已满则调用拒绝策略,拒绝接受新增任务
未满则新增非核心worker处理该任务
同时,当我们设置阻塞队列的时候 如果采用 阻塞队列时如果 采用无边界的队列,或者不设置边界,在极端情况下对应用是危险的,会因为 Task的堆积发生OOM,这也是阿里大佬在小本本上要求自己去实现ThreadLocalPool 而不使用Executors中提供的线程池的原因。
实现自己的线程池拒绝策略就是这个接口,在线程池已满的情况下,我们可以把任务放进MQ,Redis,
应用内部队列中保存起来,找特定的时间窗口再去执行,当然,具体情况具体分析,反正接口,他就在那里public interface RejectedExecutionHandler { void rejectedExecution(Runnable r, ThreadPoolExecutor executor); }
AbortPolicy(默认):直接报错
DiscardPolicy:不报错,悄悄的就丢了,注意是悄悄的,什么反应都没有
DiscardOldestPolicy:不报错,悄悄的把队列中等得最久得丢了
CallerRunsPolicy:调用者自己处理
2,不要使用没有边界的队列
3,拒绝策略需结合业务需求慎重选择,当然如果项目规模不大,且并发量低请忽略,默认即可,因为根本走不到那一步,但是咱不能不知道
4,码字不易,如果您老吃得好,欢迎再来,如果要端回家,麻烦给打个标,注明本店位置,下次再见
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算