Java 并发系列(一) ThreadPoolExecutor源码解析及理解
程序员文章站
2022-12-28 18:08:31
ThreadPoolExecutor 它是线程池最核心的类, 这里对核心的方法做简要的剖析(会持续更新),以加深对线程池运行原理的理解。 1. 核心成员变量及相关方法 1 // ctl非常重要,用整型表示,共32位,其中**高3位代表线程池状态,低29位代表工作线程数**; 2 // 线程池状态初始 ......
threadpoolexecutor
它是线程池最核心的类, 这里对核心的方法做简要的剖析(会持续更新),以加深对线程池运行原理的理解。
1. 核心成员变量及相关方法
1 // ctl非常重要,用整型表示,共32位,其中**高3位代表线程池状态,低29位代表工作线程数**; 2 // 线程池状态初始化为running,工作线程数为0 3 private final atomicinteger ctl = new atomicinteger(ctlof(running, 0)); 4 5 // 偏移量29 6 private static final int count_bits = integer.size - 3; 7 8 // 理论最大线程数(约500万) 9 private static final int capacity = (1 << count_bits) - 1; 10 11 // -1左偏移29位(下同),运行中状态,既能接收新提交的任务,又能执行阻塞队列中的任务 12 private static final int running = -1 << count_bits; 13 14 // 关闭状态,不再接收新提交的任务,但还能继续执行阻塞队列中的任务(调用shutdown()可以进入此状态) 15 private static final int shutdown = 0 << count_bits; 16 17 // 停止状态,不再接收新提交的任务,也不再执行队列中的任务;而且会尝试中断正在执行的工作线程(调用shutdownnow()可以进入此状态) 18 private static final int stop = 1 << count_bits; 19 20 // 清理状态,当workcount(工作线程数)为0,且队列也为空时就是此状态 21 // shutdown -> tidying 线程数为0,队列也为空时会自动进入改状态 22 // stop -> tidying 线程数为0时,就会自动进入该状态 23 private static final int tidying = 2 << count_bits; 24 25 // 终结状态 可以通过调用awaittermination方法来来等待线程池彻底终结 26 private static final int terminated = 3 << count_bits; 27 28 // 获取线程池运行状态;因为capacity为29个1,取反后是29个0,再通过&运算会取出最高的3位 29 private static int runstateof(int c) { return c & ~capacity; } 30 31 // 获取线程池中线程数;取出最低的29位 32 private static int workercountof(int c) { return c & capacity; } 33 34 // 将运行状态与线程数拼接起来,共有恰好有32位(因为rs已经左偏移29位了!) 35 private static int ctlof(int rs, int wc) { return rs | wc; }
2. 核心构造方法
1 /* 2 * 1. 共有7个参数 3 * 2. 具体实现不再细说,只简单说下各个作用(就是使用流程) 4 * corepoolsize: 核心线程数,如果总工作线程数小于核心线程数, 有新任务时则会继续创建新的线程 5 * maximumpoolsize: 最大线程数,理论上包含了核心线程数和非核心线程数 6 * keepalivetime: 一般上(allowcorethreadtimeout=false)是指非核心线程没有任务执行的存活时间(可以通过gettask()方法去分析) 7 * timeunit: keepalivetime的时间单位 8 * workqueue: 阻塞队列,其中包含有synchronousqueue, arrayblockingqueue, linkedblockingqueue; 存放核心线程执行不过来时被提交的任务 9 * threadfactory: 线程工厂,创建线程的地方 10 * handler: 拒绝策略,线程池满时会执行该策略rejectedexecution()方法;自带有4种拒绝策略,默认使用抛异常拒绝策略,另有什么都不做策略,用调用者线程执行任务策略,抛弃最旧任务策略 11 * 12 * 注意:1. 核心线程和非核心线程只是个逻辑的概念,某个线程被创建后,一开始可能是核心的,到后来会变成非核心的,身份并不固定。(看具体gettask()时会不会得到null) 13 * 2. 流程归总:当新任务被提交后,当工作线程数小于核心核心线程数时,会继续创建线程来处理此任务,否则会将其放在阻塞队列中;若阻塞队列已满,则会创建线程来处理此任务;若创建线程失败(不小于了最大线程数),则会执行拒绝策略。 14 */ 15 public threadpoolexecutor(int corepoolsize, 16 int maximumpoolsize, 17 long keepalivetime, 18 timeunit unit, 19 blockingqueue<runnable> workqueue, 20 threadfactory threadfactory, 21 rejectedexecutionhandler handler) { 22 if (corepoolsize < 0 || 23 maximumpoolsize <= 0 || 24 maximumpoolsize < corepoolsize || 25 keepalivetime < 0) 26 throw new illegalargumentexception(); 27 if (workqueue == null || threadfactory == null || handler == null) 28 throw new nullpointerexception(); 29 this.acc = system.getsecuritymanager() == null ? 30 null : 31 accesscontroller.getcontext(); 32 this.corepoolsize = corepoolsize; 33 this.maximumpoolsize = maximumpoolsize; 34 this.workqueue = workqueue; 35 this.keepalivetime = unit.tonanos(keepalivetime); 36 this.threadfactory = threadfactory; 37 this.handler = handler; 38 }
3. 疑问
1. 线程池属于terminated后,是怎么样释放资源的?terminated()方法是空实现?
2. execute()添加到队列后为什么还要recheck?
上一篇: Linux中文件与目录对应的硬链接与软链接方式总结
下一篇: 溢出之后的值
推荐阅读
-
Java 并发系列(一) ThreadPoolExecutor源码解析及理解
-
死磕 java同步系列之ReentrantLock源码解析(一)——公平锁、非公平锁
-
Java I/O系列(一)InputStream源码分析及理解
-
【Java并发编程】21、线程池ThreadPoolExecutor源码解析
-
Java并发编程系列一:Future和CompletableFuture解析与使用
-
Java并发系列[10]----ThreadPoolExecutor源码分析
-
Java定时任务(一) Timer及TimerTask的案例解析及源码分析
-
Java 并发系列(一) ThreadPoolExecutor源码解析及理解
-
Java并发编程系列一:Future和CompletableFuture解析与使用
-
Java I/O系列(一)InputStream源码分析及理解