线程属于稀缺资源,对于线程的创建规则,引用《阿里巴巴 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. 多数据源(sql server 2008,二个数据库不ip,)

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  2. JWT--无状态单点登录

    序言 传统的 seesion 认证存在的问题: 1)用户信息存储在内存中,用户规模大之后增加服务器开销:2)由于登录信息存储在内存中,限制了登录机器,不利于分布式站点. JWT JWT无状态登录 常规 ...

  3. 如何在ASP.NET Core中上传超大文件

    HTML部分 <%@PageLanguage="C#"AutoEventWireup="true"CodeBehind="index.aspx. ...

  4. HDU 4348 SPOJ 11470 To the moon

    Vjudge题面 Time limit 2000 ms Memory limit 65536 kB OS Windows Source 2012 Multi-University Training C ...

  5. 170815-关于Session知识点

    Cookie:实际上就是一个头.               服务器会创建Cookie,并且将Cookie以一个响应头的形式发送给浏览器               浏览器收到Cookie以后,会保存 ...

  6. CSS3实现图片黑白滤镜居中,hover缩放遮罩的效果

       hover: 在前端开发中经常会遇到项目展示,往往会采用卡片方式来描述.众多网站中,普遍采用CSS3的scale()方法来实现交互. 本文即是利用纯CSS实现图片居中缩放,此类方法各大网站均有应 ...

  7. css基础—字体那些事

    css基础-字体那些事 1. 首先讲字的大小样式等 字体大小 font-size: 40px; 文字字体 font-family: "宋体",Arial; 文字样式 font-st ...

  8. mui初级入门教程(四)— 再谈webview,从小白变“大神”!

    文章来源:小青年原创发布时间:2016-06-05关键词:mui,html5+,webview转载需标注本文原始地址: http://zhaomenghuan.github.io/#!/blog/20 ...

  9. 阿里云配置通用服务的坑 ssh: connect to host 47.103.101.102 port 22: Connection refused

    1.~ wjw$ ssh root@47.103.101.102 ssh: connect to host 47.103.101.102 port 22: Connection refused ssh ...

  10. 对象数组(JSON) 根据某个共同字段 分组

    1.在前端页面用js处理 转载https://www.cnblogs.com/rysinal/p/5834446.html 为了第二种方法对比,特意把id 转化为pid var arr = [ {&q ...