线程属于稀缺资源,对于线程的创建规则,引用《阿里巴巴 Java 手册》中的一条进行说明。

  本篇从源码方面介绍ThreadPoolExecutor对象,并简要解析线程池工作原理。

  首先ThreadPoolExecutor中定义了几个线程池状态常量。

// runState is stored in the high-order bits
private static final int RUNNING = - << COUNT_BITS;
private static final int SHUTDOWN = << COUNT_BITS;
private static final int STOP = << COUNT_BITS;
private static final int TIDYING = << COUNT_BITS;
private static final int TERMINATED = << COUNT_BITS;
  • RUNNING是运行状态,线程池可以接收新任务
  • SHUTDOWN是在调用shutdown()方法以后处在的状态。表示不再接收新任务,但队列中的任务可以执行完毕
  • STOP是在调用shutdownNow()方法以后的状态。不再接收新任务,中断正在执行的任务,抛弃队列中的任务
  • TIDYING表示所有任务都执行完毕
  • TERMINATED为中止状态,调用terminated()方法后,尝试更新为此状态

  看一下构造方法的参数

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory, RejectedExecutionHandler handler) {
}
  • corePoolSize是线程池的核心线程数
  • maximumPoolSize是线程池允许的最大线程数
  • keepAliveTime为线程空闲时的存活时间
  • unit是keepAliveTime的单位
  • workQueue是用来保存等待被执行的线程的队列
  • threadFactory,线程工厂,通常使用默认工厂,定义了线程名称生成规则。
  • handler是当最大线程数和队列都满了以后,线程池的处理策略

  这里可以简单看下JDK中已有的4种饱和策略handler:

  • AbortPolicy:默认策略,直接抛出异常,throw new RejectedExecutionException
  • CallerRunsPolicy:如果线程池没有中止,直接用调用者的线程资源执行任务
  • DiscardOldestPolicy:如果线程池没有中止,移除队列第一个任务,再执行当前任务
  • DiscardPolicy:什么也不做,直接抛弃这个任务

  也可以自定义饱和策略,只需实现RejectedExecutionHandler接口。

  

  再看一下JDK中的workQueue队列:

  • ArrayBlockingQueue:基于数组实现
  • LinkedBlockingQueue:基于链表实现,默认容量Integer.MAX_VALUE
  • SynchronousQuene:不存储元素,每个插入操作必须等待另一个线程调用移除操作
  • priorityBlockingQuene:具有优先级的队列

  JDK提供了Executors工厂类。这里面有几种实例化线程池的方法:

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

  指定了线程数,且corePoolSize == maximumPoolSize。

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

  可缓存线程池。最大线程数达到Integer.MAX_VALUE。所以在使用该线程池时,一定要控制并发数,不然会创建很多线程,占用大量资源。

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

  只有一个线程的线程池,可以保证提交任务的顺序执行。

  上面的实例方法都很方便,但是在开发中创建线程池时,最好不好使用Executors类中的初始化方法。见《阿里巴巴 Java 手册》:

  

  

  最后看一下ThreadPoolExecutor执行任务的方法

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();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == )
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
  • 判断command是否为空
  • 获取线程状态
  • 计算线程池中的线程数量,如果数量小于corePoolSize,就创建一个新线程执行任务
  • 如果线程池正在运行状态,且写入队列成功。
  • 再次获取线程池状态。判断,如果线程状态变成了非运行状态,就从队列中移除任务,调用reject()方法执行饱和策略handler
  • 如果线程池为空,就创建一个新线程执行任务
  • 如果第4步判断没有通过,尝试建立线程执行任务,若没有成功,就执行饱和策略handler

  以一张简单的流程图描述上面的步骤:

  

  

  

  

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

  1. jdk线程池ThreadPoolExecutor工作原理解析(自己动手实现线程池)(一)

    jdk线程池ThreadPoolExecutor工作原理解析(自己动手实现线程池)(一) 线程池介绍 在日常开发中经常会遇到需要使用其它线程将大量任务异步处理的场景(异步化以及提升系统的吞吐量),而在 ...

  2. 21.线程池ThreadPoolExecutor实现原理

    1. 为什么要使用线程池 在实际使用中,线程是很占用系统资源的,如果对线程管理不善很容易导致系统问题.因此,在大多数并发框架中都会使用线程池来管理线程,使用线程池管理线程主要有如下好处: 降低资源消耗 ...

  3. Java8线程池ThreadPoolExecutor底层原理及其源码解析

    小侃一下 日常开发中, 或许不会直接new线程或线程池, 但这些线程相关的基础或思想是非常重要的, 参考林迪效应; 就算没有直接用到, 可能间接也用到了类似的思想或原理, 例如tomcat, jett ...

  4. 线程池ThreadPoolExecutor工作原理

    前言 工作原理 如果使用过线程池,细心的同学肯定会注意到,new一个线程池,但是如果不往里面提交任何任务的话,main方法执行完之后程序会退出,但是如果向线程池中提交了任务的话,main方法执行完毕之 ...

  5. 线程池ThreadPoolExecutor使用原理

    本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片.视频等原文的内容) 若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接:https://www.cn ...

  6. 从源码角度来分析线程池-ThreadPoolExecutor实现原理

    作为一名Java开发工程师,想必性能问题是不可避免的.通常,在遇到性能瓶颈时第一时间肯定会想到利用缓存来解决问题,然而缓存虽好用,但也并非万能,某些场景依然无法覆盖.比如:需要实时.多次调用第三方AP ...

  7. Java线程池ThreadPoolExecutor使用和分析(三) - 终止线程池原理

    相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池Thr ...

  8. Java 线程池(ThreadPoolExecutor)原理分析与使用

    在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...

  9. Java 线程池(ThreadPoolExecutor)原理解析

    在我们的开发中“池”的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 有关java线程技术文章还可以推荐阅读:<关于java多线程w ...

随机推荐

  1. mysql INNER JOIN关键字 语法

    mysql INNER JOIN关键字 语法 作用:在表中存在至少一个匹配时,INNER JOIN 关键字返回行.大理石平台维修 语法:SELECT column_name(s) FROM table ...

  2. Codeforces Round #579 (Div. 3) 套题 题解

    A. Circle of Students      题目:https://codeforces.com/contest/1203/problem/A 题意:一堆人坐成一个环,问能否按逆时针或者顺时针 ...

  3. PC端无论页面有没有完全撑开把footer保持在最底部(不用定位)

    最近在写项目,有的页面没有占到一屏,然后footer也就是底部就靠上了,这样很影响美观,于是在网上找了找,下面是我的成果 解决该问题的最好方法是采用CSS3提供的一种先进布局模型 :flexbox,可 ...

  4. (42)嵌入式项目中常用到的C语言技能总结

    嵌入式项目中常用到的C语言技能 1.指针 .结构体. 枚举. 联合.数组.字符串.链表七个专题 2.结构体指针.结构体的多重嵌套[结构体中嵌套结构体.结构体中嵌套枚举.联合体.结构体中嵌套函数指针.一 ...

  5. iOS-7-Cookbook

    https://github.com/liubin1777/iOS-7-Cookbook 版权声明:本文为博主原创文章,未经博主允许不得转载.

  6. mpvue 未找到app.json入口文件

    [情况1] 通过 vue init mpvue/mpvue-quickstart myproject 创建一个mpvue项目,发现项目中没有app.json文件. 解决:npm run dev 编译一 ...

  7. Understanding RequireJS for Effective JavaScript Module Loading

    Modular programming is used to break large applications into smaller blocks of manageable code. Modu ...

  8. element-ui的rules全局验证

    原文:https://www.jianshu.com/p/6a29e9e51b61 rules.js var QQV = (rule, value, callback) => { debugge ...

  9. 嵌入式Linux之telnet

    telnetd   1.busybox搭建根文件系统时telnet配置Networking Utilities——>[*]telnetd[*]Support standalone telnetd ...

  10. flex 强制垃圾回收

    java和flash的垃圾回收都是一个比较热门的话题,今天我也用一个例子来测试下flash的强制垃圾回收.主要用到的而一个类是LocalConnection. 在Flash player的debug版 ...