ThreadPoolExecutor继承自 AbstractExecutorServiceAbstractExecutorService实现了 ExecutorService 接口。

顾名思义,线程池就是保存一系列线程的“容器”。

在ThreadPoolExecutor的实现中,将这些线程保存在一个HashSet中

  1. private final HashSet<Worker> workers = new HashSet<Worker>();

其中的Worker是一个内部类,在后面会讲到。

另外有一个BlockingQueue用于保存提交到线程池的任务

  1. private final BlockingQueue<Runnable> workQueue;

corePoolSize和maximumPoolSize是ThreadPoolExecutor中的两个字段,分别表示线程池的核心线程数和最大线程数。

当我们向线程池提交一个任务时,线程池会做如下判断:

  • 如果线程池中的线程数小于corePoolSize,创建线程执行任务;
  • 否则,如果任务队列未满,将任务保存在任务队列中;
    • 否则,如果线程池中线程数小于maximumPoolSize,创建线程执行任务;

      • 否则,按照策略执行无法执行的任务。

下面是ThreadPoolExecutor的构造方法:

  1. public ThreadPoolExecutor(int corePoolSize,
  2. int maximumPoolSize,
  3. long keepAliveTime,
  4. TimeUnit unit,
  5. BlockingQueue<Runnable> workQueue,
  6. ThreadFactory threadFactory,
  7. RejectedExecutionHandler handler) {
  8. if (corePoolSize < 0 ||
  9. maximumPoolSize <= 0 ||
  10. maximumPoolSize < corePoolSize ||
  11. keepAliveTime < 0)
  12. throw new IllegalArgumentException();
  13. if (workQueue == null || threadFactory == null || handler == null)
  14. throw new NullPointerException();
  15. this.corePoolSize = corePoolSize;
  16. this.maximumPoolSize = maximumPoolSize;
  17. this.workQueue = workQueue;
  18. this.keepAliveTime = unit.toNanos(keepAliveTime);
  19. this.threadFactory = threadFactory;
  20. this.handler = handler;
  21. }

回到 Executors 构建线程池的方法

  • 构建固定大小的线程池

    1. public static ExecutorService More ...newFixedThreadPool(int nThreads) {
    2. return new ThreadPoolExecutor(nThreads, nThreads,
    3. 0L, TimeUnit.MILLISECONDS,
    4. new LinkedBlockingQueue<Runnable>());
    5. }
  • 构建缓冲池,需要的时候才新建线程,新建出来的线程不会被回收而是用于后面的重用
    1. public static ExecutorService More ...newCachedThreadPool() {
    2. return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
    3. 60L, TimeUnit.SECONDS,
    4. new SynchronousQueue<Runnable>());
    5. }

再看ThreadPoolExecutor的execute()方法,该方法是Executor接口定义的方法(ExecutorService接口继承自Executor):

  1. public void execute(Runnable command) {
  2. if (command == null)
  3. throw new NullPointerException();
  4. /*
  5. * Proceed in 3 steps:
  6. *
  7. * 1. If fewer than corePoolSize threads are running, try to
  8. * start a new thread with the given command as its first
  9. * task. The call to addWorker atomically checks runState and
  10. * workerCount, and so prevents false alarms that would add
  11. * threads when it shouldn't, by returning false.
  12. * 当池子大小小于corePoolSize就新建线程,并处理请求
  13. *
  14. * 2. If a task can be successfully queued, then we still need
  15. * to double-check whether we should have added a thread
  16. * (because existing ones died since last checking) or that
  17. * the pool shut down since entry into this method. So we
  18. * recheck state and if necessary roll back the enqueuing if
  19. * stopped, or start a new thread if there are none.
  20. * 如果任务可以被插入到workQueue,需要复查当前运行状态
  21. *
  22. * 3. If we cannot queue task, then we try to add a new
  23. * thread. If it fails, we know we are shut down or saturated
  24. * and so reject the task.
  25. * 如果任务无法被插入到workQueue,则调用reject方法
  26. */
  27. int c = ctl.get();
  28. if (workerCountOf(c) < corePoolSize) {
  29. if (addWorker(command, true))
  30. return;
  31. c = ctl.get();
  32. }
  33. if (isRunning(c) && workQueue.offer(command)) {
  34. int recheck = ctl.get();
  35. if (! isRunning(recheck) && remove(command))
  36. reject(command);
  37. else if (workerCountOf(recheck) == 0)
  38. addWorker(null, false);
  39. }
  40. else if (!addWorker(command, false))
  41. reject(command);
  42. }

其中, reject(command)就是任务无法执行,按照预先定义的方法执行无法执行的任务。

addWorker是将提交任务的核心方法:

  1. private boolean addWorker(Runnable firstTask, boolean core) {
  2. retry:
  3. for (;;) {
  4. int c = ctl.get();
  5. int rs = runStateOf(c);
  6.  
  7. // Check if queue empty only if necessary.
  8. if (rs >= SHUTDOWN &&
  9. ! (rs == SHUTDOWN &&
  10. firstTask == null &&
  11. ! workQueue.isEmpty()))
  12. return false;
  13.  
  14. for (;;) {
  15. int wc = workerCountOf(c);
  16. if (wc >= CAPACITY ||
  17. wc >= (core ? corePoolSize : maximumPoolSize))
  18. return false;
  19. if (compareAndIncrementWorkerCount(c))
  20. break retry;
  21. c = ctl.get(); // Re-read ctl
  22. if (runStateOf(c) != rs)
  23. continue retry;
  24. // else CAS failed due to workerCount change; retry inner loop
  25. }
  26. }
  27.  
  28. boolean workerStarted = false;
  29. boolean workerAdded = false;
  30. Worker w = null;
  31. try {
  32. final ReentrantLock mainLock = this.mainLock;
  33. w = new Worker(firstTask);
  34. final Thread t = w.thread;
  35. if (t != null) {
  36. mainLock.lock();
  37. try {
  38. // Recheck while holding lock.
  39. // Back out on ThreadFactory failure or if
  40. // shut down before lock acquired.
  41. int c = ctl.get();
  42. int rs = runStateOf(c);
  43.  
  44. if (rs < SHUTDOWN ||
  45. (rs == SHUTDOWN && firstTask == null)) {
  46. if (t.isAlive()) // precheck that t is startable
  47. throw new IllegalThreadStateException();
  48. workers.add(w);
  49. int s = workers.size();
  50. if (s > largestPoolSize)
  51. largestPoolSize = s;
  52. workerAdded = true;
  53. }
  54. } finally {
  55. mainLock.unlock();
  56. }
  57. if (workerAdded) {
  58. t.start();
  59. workerStarted = true;
  60. }
  61. }
  62. } finally {
  63. if (! workerStarted)
  64. addWorkerFailed(w);
  65. }
  66. return workerStarted;
  67. }

再看一下线程池中的工作线程:

  1. private final class Worker
  2. extends AbstractQueuedSynchronizer
  3. implements Runnable
  4. {
  5. /**
  6. * This class will never be serialized, but we provide a
  7. * serialVersionUID to suppress a javac warning.
  8. */
  9. private static final long serialVersionUID = 6138294804551838833L;
  10.  
  11. /** Thread this worker is running in. Null if factory fails. */
  12. final Thread thread;
  13. /** Initial task to run. Possibly null. */
  14. Runnable firstTask;
  15. /** Per-thread task counter */
  16. volatile long completedTasks;
  17.  
  18. /**
  19. * Creates with given first task and thread from ThreadFactory.
  20. */
  21. Worker(Runnable firstTask) {
  22. setState(-1); // inhibit interrupts until runWorker
  23. this.firstTask = firstTask;
  24. this.thread = getThreadFactory().newThread(this);
  25. }
  26.  
  27. /** Delegates main run loop to outer runWorker */
  28. public void run() {
  29. runWorker(this);
  30. }
  31.  
  32. // Lock methods
  33. //
  34. // The value 0 represents the unlocked state.
  35. // The value 1 represents the locked state.
  36.  
  37. protected boolean isHeldExclusively() {
  38. return getState() != 0;
  39. }
  40.  
  41. protected boolean tryAcquire(int unused) {
  42. if (compareAndSetState(0, 1)) {
  43. setExclusiveOwnerThread(Thread.currentThread());
  44. return true;
  45. }
  46. return false;
  47. }
  48.  
  49. protected boolean tryRelease(int unused) {
  50. setExclusiveOwnerThread(null);
  51. setState(0);
  52. return true;
  53. }
  54.  
  55. public void lock() { acquire(1); }
  56. public boolean tryLock() { return tryAcquire(1); }
  57. public void unlock() { release(1); }
  58. public boolean isLocked() { return isHeldExclusively(); }
  59.  
  60. void interruptIfStarted() {
  61. Thread t;
  62. if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
  63. try {
  64. t.interrupt();
  65. } catch (SecurityException ignore) {
  66. }
  67. }
  68. }
  69. }

ThreadPoolExecutor 线程池的实现的更多相关文章

  1. 13.ThreadPoolExecutor线程池之submit方法

    jdk1.7.0_79  在上一篇<ThreadPoolExecutor线程池原理及其execute方法>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法 ...

  2. ThreadPoolExecutor 线程池的源码解析

    1.背景介绍 上一篇从整体上介绍了Executor接口,从上一篇我们知道了Executor框架的最顶层实现是ThreadPoolExecutor类,Executors工厂类中提供的newSchedul ...

  3. j.u.c系列(01) ---初探ThreadPoolExecutor线程池

    写在前面 之前探索tomcat7启动的过程中,使用了线程池(ThreadPoolExecutor)的技术 public void createExecutor() { internalExecutor ...

  4. Java并发——ThreadPoolExecutor线程池解析及Executor创建线程常见四种方式

    前言: 在刚学Java并发的时候基本上第一个demo都会写new Thread来创建线程.但是随着学的深入之后发现基本上都是使用线程池来直接获取线程.那么为什么会有这样的情况发生呢? new Thre ...

  5. ThreadPoolExecutor 线程池

    TestThreadPoolExecutorMain package core.test.threadpool; import java.util.concurrent.ArrayBlockingQu ...

  6. 十、自定义ThreadPoolExecutor线程池

    自定义ThreadPoolExecutor线程池 自定义线程池需要遵循的规则 [1]线程池大小的设置 1.计算密集型: 顾名思义就是应用需要非常多的CPU计算资源,在多核CPU时代,我们要让每一个CP ...

  7. Executors、ThreadPoolExecutor线程池讲解

    官方+白话讲解Executors.ThreadPoolExecutor线程池使用 Executors:JDK给提供的线程工具类,静态方法构建线程池服务ExecutorService,也就是Thread ...

  8. SpringBoot项目框架下ThreadPoolExecutor线程池+Queue缓冲队列实现高并发中进行下单业务

    主要是自己在项目中(中小型项目) 有支付下单业务(只是办理VIP,没有涉及到商品库存),目前用户量还没有上来,目前没有出现问题,但是想到如果用户量变大,下单并发量变大,可能会出现一系列的问题,趁着空闲 ...

  9. 手写线程池,对照学习ThreadPoolExecutor线程池实现原理!

    作者:小傅哥 博客:https://bugstack.cn Github:https://github.com/fuzhengwei/CodeGuide/wiki 沉淀.分享.成长,让自己和他人都能有 ...

  10. 源码剖析ThreadPoolExecutor线程池及阻塞队列

    本文章对ThreadPoolExecutor线程池的底层源码进行分析,线程池如何起到了线程复用.又是如何进行维护我们的线程任务的呢?我们直接进入正题: 首先我们看一下ThreadPoolExecuto ...

随机推荐

  1. go操作数据库 Go-SQL-Driver/MySQL 使用详解

    go操作mysql的驱动包很多,这里讲解当下比较流行的Go-SQL-Driver/MySQL1.下载安装 执行下面两个命令: 下载:go get github.com/Go-SQL-Driver/My ...

  2. xps13 关机充电 右边的usb口

    bios里设置了 usb powershare但关机的时候还是不能充电 度娘了一下,发现不解决问题,只能放狗了.果然谷歌里搜到答案,是windows的电源策略. I figured it out. A ...

  3. ios项目开发(天气预报项目):通过经纬度获取当前城市名称

     1 . 在项目里加入� CoreLocation.framework 2 .在 .h 文件输入例如以下: 1.#import <CoreLocation/CLLocation.h> ...

  4. 使用air进行移动app开发常见功能和问题(二)

    1.  Air如何判断android.ios 平台网络连接状态? Android,使用as3原生api: if(NetworkInfo.isSupported)//只有android支持 Networ ...

  5. VirtualBox中centos网络配置

    VirtualBox图形界面下有四种网络接入方式,它们分别是: 1.NAT 网络地址转换模式(NAT,Network Address Translation) 2.Bridged Adapter 桥接 ...

  6. 通过代码设置button中文字的对齐方式

    // button.titleLabel.textAlignment = NSTextAlignmentLeft; 这句无效 button.contentHorizontalAlignment = U ...

  7. [转]Oracle字符串拼接的方法

    本文转自:http://www.blogjava.net/liuwuping12064915/archive/2011/06/27/353096.html 和其他数据库系统类似,Oracle字符串连接 ...

  8. Java内存溢出示例

    按照java内存的结构,发生内存溢出的地方常在于堆.栈.方法区.直接内存. 一.堆溢出 堆溢出原因莫过于对象太多导致,看代码: /** * java 堆溢出 * VM Args:-Xms20m -Xm ...

  9. jQuery UI - draggable 中文API

    ·概述 在任何DOM元素启用拖动功能.通过单击鼠标并拖动对象在窗口内的任何地方移动. 官方示例地址:http://jqueryui.com/demos/draggable/ 所有的事件回调函数都有两个 ...

  10. 【转】Oracle - 数据库的实例、表空间、用户、表之间关系

    [转]Oracle - 数据库的实例.表空间.用户.表之间关系 完整的Oracle数据库通常由两部分组成:Oracle数据库和数据库实例. 1) 数据库是一系列物理文件的集合(数据文件,控制文件,联机 ...