4、JUC Executors 使用&源码分析

未完待续,写作中…

1、JUC里有几种线程池?各自的使用场景?

FixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}

CachedThreadPool

public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}

SingleThreadExecutor

public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
static class FinalizableDelegatedExecutorService
extends DelegatedExecutorService {
FinalizableDelegatedExecutorService(ExecutorService executor) {
super(executor);
}
protected void finalize() {
super.shutdown();
}
}
4.1、简单使用线程池
public class FixedThreadPoolTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i<6; i++) {
executorService.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName());
ThreadUtils.sleep(1000);
}
});
}
}
}

​ExecutorService executorService = Executors.newFixedThreadPool(3)​​,创建一个拥有 固定数量线程 的线程池。

4.1.1、Executors、ExecutorService命名

我初学JUC 线程池的时候,很不能理解,为什么要用 ​​Executors​​​ 这个命名的工具类来创建线程池? 线程池为什么还是​​ExecutorService​​ 接口的实现类?

不知道大家有没有这个疑惑?

线程池的作用是干嘛的?单纯的线程池没什么意义,执行任务才是线程池存在的意义。所以从执行任务这个角度来看,使用 ​​Executors​​​ 和 ​​ExectutorService​​ 两个命名就显得合情合理了!!

ThreadPoolExecutor 源码

NO.

项目

二进制

A

CAPACITY

0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

B

~CAPACITY

1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

1

RUNNING(-1)

1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

2

SHUTDOWN(0)

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

3

STOP(1)

0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

4

TIDYING(2)

0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

5

TERMINATED(3)

1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

private static int runStateOf(int c)     { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }

int的前3位表示 状态,通过与​​~CAPACITY​​​进行与运算可以取得(​​~CAPACITY​​​ 的前三位为全1)
int的后29位表示 线程数量,通过与​​CAPACITY​​​进行与运算可以取得(​​CAPACITY​​ 的后29位为全1)

点击参考:​​反码 & 为什么使用反码​​

java.util.concurrent.ThreadPoolExecutor#execute源码:

public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();

int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))// 新增工作线程
return;
c = ctl.get();
}
// 当前 "线程池处于RUNNING状态",则 "添加当前任务到任务队列"
if (isRunning(c) && workQueue.offer(commxand)) {
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);
}
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;

for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}

boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());

if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}

⭐️ addWorker(command, true) 上面时候返回 false ?

1、JUC里有几种线程池?各自的使用场景?

1、fixed(固定数量的线程);
使用 固定数量的线程 & 无界队列 来处理你提交的任务,只有指定数量的线程来处理任务。
这些线程都处于运行中时提交任务,任务需要放入无界队列中等待处理。

2 、cached(线程数量不固定,无论来多少任务都是不停的创建线程来执行,如果线程空闲了一定的时间,就会释放掉这个线程);

3 、single(线程池里就只有一个线程)

4、scheduled(提交进去的线程,会在指定的时间过后才去执行)

最最常见的线程池就是fixed线程池,线程数量是固定的,不会超过这个数量的线程,就执行你不断提交的任务