Java基础之-ExecutorService(线程池)
Posted aquariusm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础之-ExecutorService(线程池)相关的知识,希望对你有一定的参考价值。
今天看的源码是线程池的部分,记录下,源码看的jdk8的。
主要是讲述下,创建线程池的过程,以及绘制的原理图片。
从线程池的execute代码开始入手
【源码一】
java.util.concurrent.ThreadPoolExecutor.execute(Runnable command)
/** * Executes the given task sometime in the future. The task * may execute in a new thread or in an existing pooled thread. * * If the task cannot be submitted for execution, either because this * executor has been shutdown or because its capacity has been reached, * the task is handled by the current {@code RejectedExecutionHandler}. * * @param command the task to execute * @throws RejectedExecutionException at discretion of * {@code RejectedExecutionHandler}, if the task * cannot be accepted for execution * @throws NullPointerException if {@code command} is null */ public void execute(Runnable command) { if (command == null) throw new NullPointerException(); /* * Proceed in 3 steps: * * 1. If fewer than corePoolSize threads are running, try to * start a new thread with the given command as its first * task. The call to addWorker atomically checks runState and * workerCount, and so prevents false alarms that would add * threads when it shouldn‘t, by returning false. * * 2. If a task can be successfully queued, then we still need * to double-check whether we should have added a thread * (because existing ones died since last checking) or that * the pool shut down since entry into this method. So we * recheck state and if necessary roll back the enqueuing if * stopped, or start a new thread if there are none. * * 3. If we cannot queue task, then we try to add a new * thread. If it fails, we know we are shut down or saturated * and so reject the task. */ int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); } else if (!addWorker(command, false)) reject(command); }
一句 int c = ctl.get()直接整懵逼了,于是开始翻到开头看
java.util.concurrent.ThreadPoolExecutor文件开头:
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPACITY = (1 << COUNT_BITS) - 1; // runState is stored in the high-order bits 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; // Packing and unpacking ctl private static int runStateOf(int c) { return c & ~CAPACITY; } private static int workerCountOf(int c) { return c & CAPACITY; } private static int ctlOf(int rs, int wc) { return rs | wc; }
这个部分稍微有点儿难理解看了半天(还是字节处理的基础没打牢)。 (友情提示:这里理解的时候请先看下源码反码补码的知识)
(按32位系统介绍)
CONT_BITS = Integer.SIZE -3 = 32 - 3 = 29
CAPACITY = (1 << CONT_BITS) -1 = 1<<29 -1 = 2的29次方 -1 = 536870911
-1二进制:11111111111111111111111111111111
0二进制:0
1二进制:1
2二进制:10
3二进制:11
RUNNING = -1 二进制:1111 1111 1111 1111 1111 1111 1111 1111 << 29 = 1110 0000 0000 0000 0000 0000 0000 0000
SHUTDOWN = 0 二进制:0000 0000 0000 0000 0000 0000 0000 0000 << 29 = 0000 0000 0000 0000 0000 0000 0000 0000
STOP = 1 二进制:1000 0000 0000 0000 0000 0000 0000 0000 << 29 = 10 0000 0000 0000 0000 0000 0000 0000
TIDYING = 2 二进制:1000 0000 0000 0000 0000 0000 0000 0000 << 29 = 100 0000 0000 0000 0000 0000 0000 0000
TERMINATED = 3 二进制:1100 0000 0000 0000 0000 0000 0000 0000 << 29 = 110 0000 0000 0000 0000 0000 0000 0000
CAPACITY=2的29次方 -1 = 二进制:0010 0000 0000 0000 0000 0000 0000 0000 -1 = 0001 1111 1111 1111 1111 1111 1111 1111
大家看最后一排,相当于capacity 是 0001*后边全是1, 而状态就是111*,000*,001*,010*,011*
知道这个之后大家看源码下边的三个方法:
ctlOf(int rs, int wc) { return rs | wc; }
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
这样了之后,大家看代码第一句,初始状态下:
ctl这个原子变量的值:ctlof(RUNNING, 0),ctlof方法里是: RUNNING | 0,结果还是RUNNING本身。
runStateOf 是 值与~CAPACITY与操作,也就是c & (非0001 1111 1111 1111 1111 1111 1111 1111)
即:c与1110 0000 0000 0000 0000 0000 0000 0000的与,在与操作下有一个是0,结果就是0了,~CAPACITY后29位全是0,其实也就是前三位的运算。这是算状态
workerCountOf 是 值与CAPACITY的与操作,也就是c与0001 1111 1111 1111 1111 1111 1111 1111的与,CAPACITY前三位全是0,其实就是跟后29位的运算。这是容量的运算
这样大家看懂了吧,其实状态就是32位字节里,前3位表示状态,后29位是容量。
用二进制表示,这样容量就是0到2的29次方。前三位永远留下来,是状态位。
讲到这儿,我们就能继续下面的故事了。
!-- p.p1>!-- p.p1>!-- p.p1>!-- p.p1>!-- p.p1>!-- p.p1>!-- p.p1>
以上是关于Java基础之-ExecutorService(线程池)的主要内容,如果未能解决你的问题,请参考以下文章
Java 线程池ExecutorService运行原理 和FutureTask 的使用
Java--多线程之生产者消费者模式;线程池ExecutorService