Java线程池核心原理剖析
在系统开发时,我们经常会遇到“池”的概念。使用池一种以空间换时间的做法,通常在内存中事先保存一系列整装待命的对象,以供后期供其他对象随时调用。常见的池有:数据库连接池,socket连接池,线程池等。今天我们就来看一下线程池的概念。
◆
Executor
◆
JDK为我们提供了一套Executor框架来方便我们来管理和使用线程池。
打开java.util.concurrent.Executors类,我们可以发现JDK为我们提供了那么多的方法来帮助我们高效快捷的创建线程池:
1 |
public static ExecutorService newFixedThreadPool(int nThreads);//创建一个固定数目的、可重用的线程池 |
上方简单列举了几个Executor框架为我们提供的创建线程池的方法,这些线程池拥有各种各样的功能,我想当你刚刚开始使用线程的时候google如何使用线程池的时候大部分文章都是教你如何使用上方的一些方法创建一个线程池。但是如果你去查看他们的源码就会发现他们最后构造的时候都调用了同一个构造方法。(除了newWorkStealingPool之外,这个我们在下篇文章再讨论)
1 |
ThreadPoolExecutor(int corePoolSize,//线程池线程数量 |
上方的4个参数我想你看到了就会明白了,现在我们着重来讲一下下面的三个参数。
◆
WorkQueue
◆
参数workQueue是用来存放已提交但还未执行的任务,JDK为我们提供了一下实现:
直接提交队列SynchronousQueue
1 |
当新任务过来的时候它是这样处理的: |
因此使用这个队列时一定要设置很大的maximumPoolSize
有界的任务队列ArrayBlockingQueue
1 |
if(当前线程数<corePoolSize){
|
无界的任务队列LinkedBlockingDeque
1 |
if(当前线程数<corePoolSize){
|
◆
线程工厂
◆
第六个参数threadFactory是为线程池中创建线程的,我们使用Executor框架创建的线程就是有threadFactory提供的。我们看一下JDK提供的默认的threadFactory:
1 |
static class DefaultThreadFactory implements ThreadFactory {
|
重点关注一下其中的newThread方法,看到这个我想你就明白了为什么你使用线程池创建出来的线程打印的时候名字的来源,还有是否是守护线程和优先级等属性的来源了。
◆
拒绝策略
◆
看到刚刚的几种任务队列我们发现当任务过多时是需要指定拒绝策略来进行拒绝呢,那么JDK又为我们提供了哪些拒绝策略呢。
1 |
AbortPolicy直接抛出异常。 |
◆
线程池的扩展
◆
ThreadPoolExecutor不仅仅能够创建各种各样的线程来帮助我们实行功能,它还预留了三个接口来供我们进行扩展。
在runWorker方法中调用线程进行执行之前调用了beforeExecute方法,执行之后调用了afterExecute()方法
1 |
final void runWorker(Worker w) {
|
这两个方法在ThreadPoolExecutor类中是没有实现的,我们想要监控线程运行前后的数据就可以通过继承ThreadPoolExecutor类来实现这个扩展。
另外还有一个terminated()方法是在整个线程池退出的时候调用的,我们这里一并扩展。
public class ThreadPoolExecutorDemo extends ThreadPoolExecutor {
//注意这里因为ThreadPoolExecutor没有无参的构造,所以还需要重写一下构造方法。
//这里限于篇幅就不贴了
@Override
protected void afterExecute(Runnable r, Throwable t) {
System.out.println(Thread.currentThread().getId()+"执行完成");
}
@Override
protected void terminated() {
System.out.println("线程池退出");
}
}
//使用这个demo就可以验证我们扩展的结果了。
public class ThreadPoolDemo {
static class ThreadDemo extends Thread {
@Override
public void run() {
System.out.println(System.currentTimeMillis() + ":Thread ID is:" + Thread.currentThread().getId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutorDemo threadPoolExecutorDemo= new ThreadPoolExecutorDemo(5,5,0,TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>());
ThreadDemo threadDemo = new ThreadDemo();
for (int i = 0; i < 20; i++) {
threadPoolExecutorDemo.submit(threadDemo);
}
threadPoolExecutorDemo.shutdown();
}
}
本文所有源码:https://github.com/shiyujun/syj-study-demo
Java线程池核心原理剖析的更多相关文章
- Java 线程池的原理与实现 (转)
最近在学习线程池.内存控制等关于提高程序运行性能方面的编程技术,在网上看到有一哥们写得不错,故和大家一起分享. [分享]Java 线程池的原理与实现 这几天主要是狂看源程序,在弥补了一些以前知 ...
- Java线程池实现原理及其在美团业务中的实践
本文转载自Java线程池实现原理及其在美团业务中的实践 导语 随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流.使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器.J.U.C提供 ...
- 我眼中的java线程池实现原理
最近在看java线程池实现方面的源码,在此做个小结,因为网上关于线程池源码分析的博客挺多的,我也不打算重复造轮子啦,仅仅用纯语言描述的方式做做总结啦! 个人认为要想理解清楚java线程池实现原理,明白 ...
- Java线程池的原理及几类线程池的介绍
刚刚研究了一下线程池,如果有不足之处,请大家不吝赐教,大家共同学习.共同交流. 在什么情况下使用线程池? 单个任务处理的时间比较短 将需处理的任务的数量大 使用线程池的好处: 减少在创建和销毁线程上所 ...
- 并发编程(十二)—— Java 线程池 实现原理与源码深度解析 之 submit 方法 (二)
在上一篇<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.这篇文章是接着上一篇文章 ...
- 11 java 线程池 实现原理
一 关键类的实现 1 ThreadPoolExecutor类 java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类,因此如果要透彻地了解Java中的 ...
- Java 线程池(ThreadPoolExecutor)原理分析与使用
在我们的开发中"池"的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 使用线程池的好处 1.降低资源消耗 可以重复利用 ...
- Java 线程池(ThreadPoolExecutor)原理解析
在我们的开发中“池”的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 有关java线程技术文章还可以推荐阅读:<关于java多线程w ...
- Java线程池实现原理与技术(ThreadPoolExecutor、Executors)
本文将通过实现一个简易的线程池理解线程池的原理,以及介绍JDK中自带的线程池ThreadPoolExecutor和Executor框架. 1.无限制线程的缺陷 多线程的软件设计方法确实可以最大限度地发 ...
随机推荐
- 七 Git版本控制
把环境准备 主机名 node1 ip地址10.0.0.11 node2 10.0.0.12 node3 ...
- MapReduce词频统计
自定义Mapper实现 import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; impor ...
- python中hasattr()、getattr()、setattr()函数的使用
1. hasattr(object, name) 判断object对象中是否存在name属性,当然对于python的对象而言,属性包含变量和方法:有则返回True,没有则返回False:需要注意的是n ...
- Python-数据类型之元组
一:元组 元组是一个只读列表,可以使用count,index等,但是元组里的元素不能更改,也不能增加,删除 元祖的一级元素不可更改,当一级元素有可变数据类型时,如列表,列表中的元素可变 tup = ( ...
- 记忆(缓存)函数返回值:Python 实现
对于经常调用的函数,特别是递归函数或计算密集的函数,记忆(缓存)返回值可以显着提高性能.而在 Python 里,可以使用字典来完成. 例子:斐波那契数列 下面这个计算斐波那契数列的函数 fib() 具 ...
- ConcurrentHashmap详解以及在JDK1.8的更新
因为hashmap本身是非线程安全的,如果多线程对hashmap进行put操作的话,就会导致死循环等现象.ConcurrentHashMap主要就是为了应对hashmap在并发环境下不安全而诞生的,C ...
- 怎样在ASP.NET(C#) 使用Json序列化反序列化问题?
using System; using System.Collections.Generic; using System.Web; using System.Web.Script.Serializat ...
- 【java】-- 线程安全
1.线程安全问题介绍与案例分析 当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题.但是做读操作是不会发生数据冲突问题. 案例:需求现在有100张火 ...
- 腾讯云服务器、nginx部署loopback
最近在研究学习nginx,买了腾讯云服务器.在阿里上申请了域名,部署项目遇到很多问题记录一下,以备后用: 1.在腾讯服务器买好,阿里域名申请好后(也可以在腾讯上申请域名),需要添加安全组,创建不同的规 ...
- 使用Cors在WebApi中实现跨域请求,请求方式为angular的 $http.jsonp
使用Cors在WebApi中实现跨域请求 第一步,在webapi项目中安装cors 在Web API配置文件中(Global.asax)进行全局配置: public class WebApiAppli ...