Executor框架集对线程调度进行了封装,将任务提交和任务执行解耦。

它提供了线程生命周期调度的所有方法,大大简化了线程调度和同步的门槛。

Executor框架集的核心类图如下:


从上往下,可以很清晰的看出框架集的各个类,以及它们之间的关系:
Executor,是一个可以提交可执行(Runnable)任务的Object,这个接口解耦了任务提交和执行细节(线程使用、调度等),Executor主要用来替代显示的创建和运行线程;
ExecutorService提供了异步的管理一个或多个线程终止、执行过程(Future)的方法;
AbstractExecutorService提供了ExecutorService的一个默认实现,这个类通过RunnableFuture(实现类FutureTask)实现了submit, invokeAny, invokeAll几个方法;
ThreadPoolExecutor是ExecutorService的一个可配置的线程池实现,它的两个重要的配置参数:corePoolSize(线程池的基本大小,即在没有任务需要执行的时候线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。这里需要注意的是:在刚刚创建ThreadPoolExecutor的时候,线程并不会立即启动,而是要等到有任务提交时才会启动,除非调用了prestartCoreThread/prestartAllCoreThreads事先启动核心线程。再考虑到keepAliveTime和allowCoreThreadTimeOut超时参数的影响,所以没有任务需要执行的时候,线程池的大小不一定是corePoolSize。), maximumPoolSize(线程池中允许的最大线程数,线程池中的当前线程数目不会超过该值。如果队列中任务已满,并且当前线程个数小于maximumPoolSize,那么会创建新的线程来执行任务。这里值得一提的是largestPoolSize,该变量记录了线程池在整个生命周期中曾经出现的最大线程个数。为什么说是曾经呢?因为线程池创建之后,可以调用setMaximumPoolSize() 改变运行的最大线程的数目。);
ScheduledExecutorService 是添加了调度特性(延迟或者定时执行)的ExecutorService;
ScheduledThreadPoolExecutor是具有调度特性的ExecutorService的池化实现;
Executors是一个Executor, ExecutorService, ScheduledExecutorService, ThreadFactory, Callable的工具类,它能满足大部分的日常应用场景。使用它创建线程池:

接下来,分析下ThreadPoolExecutor的实现。

ThreadPoolExecutor的作者Doug Lea,他将workerCount(线程池当前有效线程数)和runState(线程池当前所处状态)放置到一个原子变量ctl(AtomicInteger)上,原子变量高三位保存runStatus,低29位保存workerCount。因此,ThreadPoolExecutor(JDK8)支持的最大线程数为2^29-1。线程池状态有以下五中:

RUNNING(正常运行,-1):  Accept new tasks and process queued tasks
   SHUTDOWN(关闭,0): Don't accept new tasks, but process queued tasks
   STOP(停止,1):     Don't accept new tasks, don't process queued tasks, and interrupt in-progress tasks
   TIDYING(整理中,2):  All tasks have terminated, workerCount is zero, the thread transitioning to state TIDYING will run the terminated() hook method
   TERMINATED(终结,3): terminated() has completed

线程池状态的变迁,并不严格按照数字增加变化:

RUNNING -> SHUTDOWN
        On invocation of shutdown(), perhaps implicitly in finalize()
     (RUNNING or SHUTDOWN) -> STOP
        On invocation of shutdownNow()
    SHUTDOWN -> TIDYING
        When both queue and pool are empty
    STOP -> TIDYING
        When pool is empty
    TIDYING -> TERMINATED
        When the terminated() hook method has completed
     Threads waiting in awaitTermination() will return when the
     state reaches TERMINATED.

当前工作线程计数以及线程池的状态变迁,通过ctl原子变量的CAS操作完成。

ThreadPoolExecutor会将所有提交的任务放置到workQueue中,它是一个BlockingQueue.

所有的工作线程集(workers,HashSet<Worker>)的获取和预定,使用一个final的ReentrantLock(mainLock)控制,还有mainLock上的等待条件termination(Condition)。

largestPoolSize(最大池容量),completedTaskCount(已完成线程计数)等私有变量,通过mainLock控制访问。

threadFactory(volatile,线程工厂,工厂模式的典型运用),所有的线程通过addWorker方法,间接调用这个工厂创建,以下为Executors中的DefaultThreadFactory类的默认构造方法(namePrefix非常熟悉)。

        DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}

keepAliveTime,线程等待工作的空闲时间(当allowCoreThreadTimeOut设置或者工作线程workerCount大于corePoolSize时,会超时退出,否则线程讲一直运行)

allowCoreThreadTimeOut,允许核心线程超时退出(默认为false)

corePoolSize,核心线程数目(如果没有设置allowCoreThreadTimeOut,它将是线程池中,最少活跃的线程数)

类Worker主要维护线程执行任务时的状态打断和其它功能预定,它通过继承AbstractQueuedSynchronizer来简化任务执行时锁的获取和释放,Worker没有使用可重入锁,而是实现了一个互斥锁,因为我们不想工作线程访问线程池控制变量时再次获得锁(如setCorePoolSize)。

接下来,我们看看addWorker方法,通过指定参数,它允许以核心线程运行任务。addWorker会首先检查当前的线程池状态,当前运行的线程数是否允许(添加新worker),前两项检查通过后,会尝试设置ctl中的线程计数(因为活跃工作线程数存储在ctl的低位,因此,直接自增ctl便可)。线程池计数器设置后,剩下的就是添并启动Worker,Worker集合由mainLock控制,所有workers集的修改都是由mainLock控制的。只有当集合添加成功并且新添加的线程启动成功时,线程池计数器的设置生效,否则,计数器将回退(由addWorkerFailed方法执行)。

 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;
}

只有当新添加的worker线程启动成功时,addWorker返回成功(此时worker线程启动start(),它的run方法中调用了runWorker方法),其它情况返回失败。

最后看一个方法,runWorker 方法:worker线程,不断从BlockQueu中取出任务,执行它并处理执行过程中的各种情况(如线程池的状态变化,已执行计数)。

  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();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}

runWorker方法中,直接调用了task的run()方法,大致交互过程。

Java并发编程-Executor框架集的更多相关文章

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

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

  2. (转)java并发编程--Executor框架

    本文转自https://www.cnblogs.com/MOBIN/p/5436482.html java并发编程--Executor框架 只要用到线程,就可以使用executor.,在开发中如果需要 ...

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

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

  4. java并发编程-Executor框架

    Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService,Completion ...

  5. Java 并发编程 Executor 框架

    本文部分摘自<Java 并发编程的艺术> Excutor 框架 1. 两级调度模型 在 HotSpot VM 的线程模型中,Java 线程被一对一映射为本地操作系统线程.在上层,Java ...

  6. Java并发编程-Executor框架(转)

    本文转自http://blog.csdn.net/chenchaofuck1/article/details/51606224 感谢作者 我们在传统多线程编程创建线程时,常常是创建一些Runnable ...

  7. java并发编程--Executor框架(一)

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

  8. java并发编程-Executor框架 + Callable + Future

    from: https://www.cnblogs.com/shipengzhi/articles/2067154.html import java.util.concurrent.*; public ...

  9. java 并发编程 Executor框架

    http://blog.csdn.net/chenchaofuck1/article/details/51606224 demo package executor; import java.util. ...

随机推荐

  1. Linux下安装MySQL以及一些小坑

    第一次写博客,各位凑合着看吧(假装有人看). 我这里使用的是centos7. 1.首先打开终端,查看有没有安装过MySQL: [root@localhost lyp]# rpm -qa | grep ...

  2. Python中super()的用法

    参考链接:https://www.cnblogs.com/shengulong/p/7892266.html super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是 ...

  3. MariaDB 备份与日志管理(13)

    MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可MariaDB的目的是完全兼容MySQL,包括API和命令行,MySQL由于现在闭源了,而能轻松成为MySQ ...

  4. WINDOWS平台下的栈溢出攻击从0到1(篇幅略长但非常值得一看)

    到1的这个过程.笔者也希望能够通过这些技术分享帮助更多的朋友走入到二进制安全的领域中.2.文章拓扑由于本篇文章的篇幅略长,所以笔者在这里放一个文章的拓扑,让大家能够在开始阅读文章之前对整个文章的体系架 ...

  5. [JavaScript] 根据指定宽度截取字符串

    /** * 根据指定宽度截取字符串 * @param desc 原始字符串 * @param width 该显示的宽度 * @param fontsize 字体大小 12px * @returns { ...

  6. supervisor 管理uwsgi 进程

    Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动 重启.它是通过fork/exec的方式把这些被管理的进 ...

  7. Alpha冲刺(3/10)——追光的人

    1.队友信息 队员学号 队员博客 221600219 小墨 https://www.cnblogs.com/hengyumo/ 221600240 真·大能猫 https://www.cnblogs. ...

  8. 以太坊ERC20代币合约案例

    一.ERC20代币合约与web3调用 ERC20代币合约在小白看来觉得很高大上,但其实就是一个代币的定义标准,方便其他dapp统一调用各种代币的方法.如图: 二.ERC20合约标准 [官方链接] co ...

  9. OAuth 2.0 安全案例回顾

    原文:http://drops.wooyun.org/papers/598 0x00 背景 纵观账号互通发展史,可以发现OAuth比起其它协议(如OpenID)更流行的原因是,业务双方不仅要求账号本身 ...

  10. 使用控制台程序搭建WebApi

    原文参考: ASP.NET Web Api 2.2: Create a Self-Hosted OWIN-Based Web Api from Scratch 新建控制台程序,引入Owin包 PM&g ...