Executor框架

Executor类:在java.util.concurrent类中,是JDK并发包的核心类。

ThreadPoolExecutor: 线程池。

Excutors: 线程池工厂,通过Executor可以创建一个特定功能的线程池。

一)、Executor框架的类的关系

Executor, ExecutorService, AbstractExcutorService, ThreadPoolExecutor,Executors

Eecutor类:

接口,只有一个execute()方法:

public interface Executor {
void execute(Runnable command);
}

ExecutorService extends Executor类:

接口,ExecutorService extends Executor,主要方法如下:

   //关闭线程池
void shutdown();
boolean isShutdown();
List<Runnable> shutdownNow();
boolean isTerminated();
<T> Future<T> submit(Callable<T> task);
//提交线程任务,并返回执行结果
Future<?> submit(Runnable task);

AbstractExecutorService类:

abstract class AbstractExecutorService implements ExecutorService,主要实现submit()方法。

    public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
//内部还是调用了execute()
execute(ftask);
return ftask;
}

ThreadPoolExecutor类:

class ThreadPoolExecutor extends AbstractExecutorService

二)、线程池的状态:

参考:https://blog.csdn.net/nobody_1/article/details/98335594

运行(RUNNING): 线程池接收新任务,并处理队列中的任务。

关机(SHUTDOWN): 线程池不接受新的任务,但接收队列的任务,调用

​ shutdown()后线程的状态。

停止(STOP): 线程池不接受新的任务,也不处理队列中的任务,并中断执行中

​ 的任务,调用shutdownNow()线程的状态。

清理(tidying): 线程池所有任务已经终止,workCount(当前线程个数)为0,过渡

​ 到清理状态的线程将运行terminated()的子方法 。

终止(terminated): terminate()方法结束后线程的状态。

    //线程池的容量11111111111111111111111111111: 29个1
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
//运行状态,-2^29,10000000000000000000000000000,1个1,29个0
private static final int RUNNING = -1 << COUNT_BITS; // 关机状态 0
private static final int SHUTDOWN = 0 << COUNT_BITS;
// 停止 2^29
private static final int STOP = 1 << COUNT_BITS;
// 清理状态 2 * 2^29
private static final int TIDYING = 2 << COUNT_BITS;
// 终止状态 3 * 2^29
private static final int TERMINATED = 3 << COUNT_BITS;

注:使用线程的高三位代表线程的状态,使用低29位代表工作线程的个数。

三)、获取池状态

private static int runStateOf(int c){
//获得高3位
return c & ~ CAPACITY;
}

四)、获得工作线程数

private static int workerCountOf(int c){
return c & Capacity;
}

五)、使用AtomicInteger变量来表示线程池状态和工作线程数量

//刚开始初始化时,线程的状态默认为RUNNING, 工作线程个数为0
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)) //rs:运行状态(runState), wc:工作线程数 (workCount)
private static int ctlOf(int rs, int wc) {
return rs | wc;
}

使用ctl可以获取线程状态和工作线程数

int c = ctl.get();

runStateOf(c): 获取运行状态

workerCountOf(c): 获取工作线程数

六)、线程池对象:ThreadPoolExecutor

1)、主要属性:


//线程池的锁
private final ReentrantLock mainLock = new ReentrantLock(); //线程池中重用线程对象
private final HashSet<Worker> workers = new HashSet<Worker>(); //最大线程个数
private int largestPoolSize;
//当线程超过最大核心线程数时的阻塞队列
private final BlockingQueue<Runnable> workQueue; //实时监控线程池的状态和工作线程的个数
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;

2)、构造方法:

    public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}

3)、参数信息:

corePoolSize: 指定了线程池中的线程数量

maximumPoolSize: 指定线程池中的最大线程数量

KeepAliveTime: 超过corePoolSize后增加的线程的空闲时间,超过这个时间线程

​ 未使用,则销毁该线程。

unit: KeepAliveTime的单位

workQueue: 任务队列,被提交但尚未被执行的任务

threadFactory: 线程工厂,一般用于创建线程。

handle: 拒绝策略,当任务太多,来不及处理,如何拒绝任务。

七)、workeQueue:等待队列

1).SynchronousQueue:直接提交的队列

​ 特点: 没有容量,每一个插入操作都要等待一个相应的删除操作。

​ 作用:应用于new CacheThreadPool线程池的workerQueue队列,不保存任务,

​ 总 是将任务提交给线程执行,如果没有空闲的进程,则尝试创建新的线

​ 程,如果进程的数量达到最大值,则执行拒绝策略。

注: 一直创建新的线程,直至线程数到达maximumPoolSize,执行拒绝策略。

2).ArrayBlockingQueue: 有界队列

​ 特点:使用构造函数,指定队列的最大容量

public ArrayBlockingQueue(int capacity){

}

​ 作用:当有新的任务要执行时,如果线程池的实际线程数小于coreSize,则会优先

​ 创建新的线程,若大于corePoolSize,则会将新任务加入等待队列,若等

​ 待队已满,在总线程数不大于maximumPoolSize的前提下创建线程,当总

​ 线程 数超过maxmmumPoolSize时执行拒绝策略。

** 注:**当线程数小于coreSize时,创建新的线程,大于coreSize时,将任务加入

​ 等待 队列,直至等待队列加满,在总线程数不超过maximumPoolSize的前

​ 提下创建线程,否则,执行拒绝策略。

3).LinkedBlockingQueue: 无界队列

​ 特点:除非资源耗尽,否则无界队列不存在任务入队失败的情况。

​ 作用:系统有任务时,若总的线程数小于corePoolSize则创建新的线程,否则,

​ 则将线程添加至等待队列中,无界队列保持快速增长,直至耗尽系统内

​ 存。

​ ** 注:** 当线程数小于corePoolSize时,创建新的线程,大于corePoolSize时,将

​ 任务加入等待队列中,直至耗尽系统内存,线程的个数一直维护在

​ corePoolSize 。

4).PriorityBlockingQueue: 优先任务队列

​ 特点:控制任务的执行先后顺序,是一个特殊的无界队列

作用:根据任务自身的优先级先后执行

八)、handler,JDK内置的四种拒绝策略

1). AbortPolicy: 直接抛出异常,阻滞系统工作

2).CallerRunsPolicy: 在调用者线程中运行当前被丢弃任务

3).DiscardOledstPolicy: 丢弃最老的一个请求,即即将被执行的一个任务,并尝试

​ 再次提交当前任务。

4).DiscardPolicy: 丢弃无法处理的任务,不予任何处理。

注:若要自定义拒绝策略,实现RejecteExecutionHandler接口,实现

​ rejectedExecution方法。

九)、execute()方法

步骤:

1)、参数传递,得到一个任务对象

2)、判断

//Runnable command 当前要执行的线程任务
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
//获取定前线程池的状态
int c = ctl.get();
//判断当前主线程数量是否超过corePoolSize,如果不超过,则新建一个线程对象
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);
} //线程池中添加新的线程,并执行线程任务
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
//获取运行状态
int rs = runStateOf(c); // Check if queue empty only if necessary.
//如若当前处于关闭、清理、终止,任务队列不为空时返回false,因为,队列不为空,说明线程个数达到核心线程的个数,不能创建新的线程值,返回false
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;
}

七)、Executors:线程池工厂

继承ThreadPoolExecutor,可以取得一个特定功能的线程池

构造方法:

注:所有的线程池的构造,其内部最终都是调用了ThreadPoolExecutor的构造方法

1)、newFixThreadPool(int nThread): 创建一个固定大小的线程池

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

2)、newSingleThreadExecutor(): 返回一个只有一个线程的线程池

    public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
  1. 、new CacheThreadPool(): 返回一个可以根据实际情况调整线程数量的线程池
    public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}

4)、new SingleThreadSchaduleExecutor(): 返回一个ScheduleExecutor对象,

retry: 标记循环位置,在continur和break后面加retry表示循环直接跳出到retry标

​ 记处。

   public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}

使用Executor框架创建线程池的更多相关文章

  1. Java 并发编程——Executor框架和线程池原理

    Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...

  2. Java 并发编程——Executor框架和线程池原理

    Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...

  3. 并发新特性—Executor 框架与线程池

    兰亭风雨 · 更新于 2018-11-14 09:00:31 并发新特性-Executor 框架与线程池 Executor 框架简介 在 Java 5 之后,并发编程引入了一堆新的启动.调度和管理线程 ...

  4. java并发编程(十七)Executor框架和线程池

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17465497   Executor框架简介 在Java 5之后,并发编程引入了一堆新的启动 ...

  5. 转:【Java并发编程】之十九:并发新特性—Executor框架与线程池(含代码)

      Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.coc ...

  6. 【Java并发编程】:并发新特性—Executor框架与线程池

    Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocur ...

  7. Java的Executor框架和线程池实现原理

    Java的Executor框架 1,Executor接口 public interface Executor { void execute(Runnable command); } Executor接 ...

  8. Java 并发编程中的 Executor 框架与线程池

    Java 5 开始引入 Conccurent 软件包,提供完备的并发能力,对线程池有了更好的支持.其中,Executor 框架是最值得称道的. Executor框架是指java 5中引入的一系列并发库 ...

  9. 并发新特性—Executor框架与线程池

    http://blog.csdn.net/ns_code/article/details/17465497 Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的AP ...

随机推荐

  1. ElasticSearch业务逻辑案例

    ElasticSearch业务逻辑案例 一.业务难题 我们有一个索引: myindex/mytype(为了方便,我们下文以a/b表示) 索引类型中的一个字段group之前是a.b.c(历史遗留问题), ...

  2. JVM 知识点补充——永久代和元空间

    之前已经讲过了不少有关 JVM 的内容,今天准备将之前没有细讲的部分进行补充,比如:永久代和元空间. 永久代 Java 的内存中有一块称之为方法区的部分,在 JDK8 之前, Hotspot 虚拟机中 ...

  3. C++沉思录笔记 —— 序幕

    #include <stdio.h>   class Trace{public: void print(const char* s) { printf("%s\n", ...

  4. Markdown进阶(1)

    对于工科生来说,在书写Markdown文本时,免不了要和上下标打交道,网上的博客大多良莠不齐,不太友好,本文想尽可能地解决一些在看完基础教程后再来书写Markdown文本时容易遇到的问题. 1.上下标 ...

  5. Redis(十三)Python客户端redis-py

    一.安装redis-py的方法 使用pip install安装redis-py C:\Users\BigJun>pip3 install redis Collecting redis Downl ...

  6. django-模板之静态文件加载(十四)

    1.在templates同级目录下建static 2.index.css 3.index.html {% load static %} <!DOCTYPE html> <html l ...

  7. ubuntu18.04 flink-1.9.0 Standalone集群搭建

    集群规划 Master JobManager Standby JobManager Task Manager Zookeeper flink01 √ √ flink02 √ √ flink03 √ √ ...

  8. 【从刷面试题到构建知识体系】Java底层-synchronized锁-2偏向锁篇

    上一篇通过构建金字塔结构,来从不同的角度,由浅入深的对synchronized关键字做了介绍, 快速跳转:https://www.cnblogs.com/xyang/p/11631866.html 本 ...

  9. Spring之Zuul初步使用(十)

    一.zuul是什么 zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用. Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架. ...

  10. SQlite 日期时间总结

    1. 时间串转时间戳,函数strftime,其参数1是固定'%s',参数2是待转换的时间串,参数3...是修饰符 (1)select strftime('%s','2004-01-01 02:34:5 ...