线程池

接口Executor

该接口只有一个方法,JDK解释如下

执行已提交的Runnable 任务的对象。此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。

不过,Executor 接口并没有严格地要求执行是异步的。在最简单的情况下,执行程序可以在调用者的线程中立即运行已提交的任务:

更常见的是,任务是在某个不是调用者线程的线程中执行的。以下执行程序将为每个任务生成一个新线程。

方法介绍如下:

void execute(Runnable command)

在未来某个时间执行给定的命令。该命令可能在新的线程、已入池的线程或者正调用的线程中执行,这由Executor 实现决定。

接口ExecutorService

ExecutorService 是对 Executor 的扩展,JDK文档解释如下:

Executor 提供了管理终止的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。

可以关闭ExecutorService,这将导致其拒绝新任务。提供两个方法来关闭 ExecutorService。shutdown() 方法在终止前允许执行以前提交的任务,而 shutdownNow()方法阻止等待任务启动并试图停止当前正在执行的任务。在终止时,执行程序没有任务在执行,也没有任务在等待执行,并且无法提交新任务。应该关闭未使用的 ExecutorService 以允许回收其资源。

通过创建并返回一个可用于取消执行和/或等待完成的 Future,方法 submit 扩展了基本方法 Executor.execute(java.lang.Runnable)。方法 invokeAny 和 invokeAll 是批量执行的最常用形式,它们执行任务 collection,然后等待至少一个,或全部任务完成(可使用 ExecutorCompletionService 类来编写这些方法的自定义变体)。

此接口中的关键是三个submit 方法,接受一个任务,并返回结果Future。

  • <T> Future<T> submit(Callable<T> task);
  • <T> Future<T> submit(Runnable task, T result);
  • Future<?> submit(Runnable task);

 

任务执行

Submit 的实际代码位于AbstractExecutorService,继承ExecutorService。来观察其三个submit方法。
不论submit 方法的参数是什么,都是先构造一个RunnableFuture ,然偶执行它,并返回它。执行和返回的都是RunnableFuture。所以RunnableFuture实现了future 接口和runnnable接口。注意这点的类型是RunnableFuture,所有接下来的execute方法执行的run方法是RunnableFuture 的具体实现类FutureTask的run方法。

来看RunnableFuture,其代码如下:

作为 Runnable 的 Future。成功执行 run 方法可以完成 Future 并允许访问其结果。以下代码可以看出 返回的实际上是FutureTask,为RunnableFuture的实现类。

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {

return new FutureTask<T>(runnable, value);}

关于 FutureTask JDK对其介绍如下:

可取消的异步计算。利用开始和取消计算的方法、查询计算是否完成的方法和获取计算结果的方法,此类提供了对Future 的基本实现。仅在计算完成时才能获取结果;如果计算尚未完成,则阻塞 get 方法。一旦计算完成,就不能再重新开始或取消计算。

可使用FutureTask 包装 Callable 或 Runnable 对象。因为 FutureTask 实现了 Runnable,所以可将 FutureTask 提交给 Executor 执行。

除了作为一个独立的类外,此类还提供了 protected 功能,这在创建自定义任务类时可能很有用。

先看其构造函数。可以看出其构造函数主要是一个 同步器的构造。同步器接受一个Callable类型的参数。

对于参数是Runnable 类型时,经过转化为Callable 类型,转化代码如下,本质上就是在Callable 的call方法中调用Runnable的run方法:

FutureTask的关键逻辑都由他的一个内部类Sync 实现。我们先暂且不管其具体实现,留在后面说。

执行

具体的逻辑如下描述:

首先判断空;

如果当前池大小 小于 核心池大小(初始就是这样),那么会执行 addIfUnderCorePoolSize这个方法。这个方法就会创建新的工作线程,且把当前任务 command 设置为他的第一个任务,并开始执行,返回true。整个execute方法结束。

  1. 否则加入到等待队列中。

    (2)只有当前池大小小于核心池大小的时候,且线程池处于RUNNING状态的时候才增加新的工作线程,并把传进来的任务作为第一个任务并开始执行。此时返回真,否则返回假。

    如果当前池大小 大于核心池的大小,或者添加新的工作线程失败(这可能是多线程环境下,竞争锁,被阻塞,其他线程已经创建好了工作线程)。那么当前任务进入到等待队列。

    如果队列满,或者线程池已经关闭,那么拒绝该任务。

     

     

    FutureTask

    此类是RunnableFuture的实现类。线程池执行的run方法是它的run方法。它委托给Sync实现,SYNC 继承AQS。

    重点看Sync。对具体任务的调用发生在innerSet(callable.call());这句调用,innerSet的方法 作用是 设置get方法的返回值。

    而get方法是需要获取锁的,所以在具体的任务没有执行完前,调用get方法会进入到阻塞状态。

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

  1. jdk线程池主要原理

    本文转自:http://blog.csdn.net/linchengzhi/article/details/7567397 正常创建一个线程的时候,我们是这样的:new thread(Runnable ...

  2. JDK线程池和Spring线程池的使用

    JDK线程池和Spring线程池实例,异步调用,可以直接使用 (1)JDK线程池的使用,此处采用单例的方式提供,见示例: public class ThreadPoolUtil { private s ...

  3. JDK 线程池

    JDK 线程池 线程池参数 在JDK的4种线程池之前, 先介绍一下线程池的几个参数 corePoolSize 线程池的核心线程数量, maximumPoolSize 线程池的最大线程数量 keepAl ...

  4. 自己动手写线程池——向JDK线程池进发

    自己动手写线程池--向JDK线程池进发 前言 在前面的文章自己动手写乞丐版线程池中,我们写了一个非常简单的线程池实现,这个只是一个非常简单的实现,在本篇文章当中我们将要实现一个和JDK内部实现的线程池 ...

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

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

  6. JDK线程池的拒绝策略

    关于新疆服务请求未带入来话原因的问题 经核查,该问题是由于立单接口内部没有成功调用接续的 “更新来电原因接口”导致的,接续测更新来电原因接口编码:NGCCT_UPDATESRFLAG_PUT ,立单接 ...

  7. JDK线程池的使用

    转载自:https://my.oschina.net/hosee/blog/614319: 摘要: 本系列基于炼数成金课程,为了更好的学习,做了系列的记录. 本文主要介绍: 1. 线程池的基本使用 2 ...

  8. juc线程池原理(六):jdk线程池中的设计模式

    一.jdk中默认线程池中的代理模式 单例类线程池只有一个线程,无边界队列,适合cpu密集的运算.jdk中创建线程池是通过Executors类中提供的静态的方法来创建的,其中的单例类线程池的方法如下: ...

  9. jdk线程池,使用手记

    Executors----------------------------------------------Executors------------------------------------ ...

随机推荐

  1. 【BIEE】06_UNION /UNION ALL集合中分类汇总求和占比字段特殊处理

    环境准备 基于[BIEE]04..中建立的事实表 通过UNION ALL后得到如下报表: 优秀员工薪水公式:CASE WHEN "EMP_FACT"."级别"= ...

  2. LoadRunner变量到参数的互换

    作者QQ:764714258,转载请说明出处,阅读此文需要良好的C基础 LoadRunner中,web性能测试使用的脚步是C语言编写的.C语言中有变量的概念,LoadRunner工具中带有参数这个概念 ...

  3. git 4种对象的理解

    git中有四种基本对象类型,可以说Git的所有操作都是通过这四种对象完成的.下图是<Git版本控制管理>中文第二版的原话,顺便吐槽一下,这本书真的翻译的一般.. 下面说下我的理解吧,首先b ...

  4. ganlia安装配置文档

    gangliaz在ubuntu中安装和配置很简单 1.  服务器端安装 sudo apt-get install ganglia-monitor ganglia-webfrontend rrdtool ...

  5. 【已解决】iView-admin Editor 组件 绑定默认值问题

    iView-admin Editor 组件 绑定默认值问题 发现 editor 组件,设置v-model 后, 修改 v-model 数据, editor组件没有自动渲染,需要手动设置渲染  this ...

  6. Ubuntu 16.04 安装opencv的各种方法(含opencv contrib扩展包安装方法)

    Ubuntu 16.04 安装opencv的各种方法(含opencv contrib扩展包安装方法) https://blog.csdn.net/ksws0292756/article/details ...

  7. 【COCOS2DX-LUA 脚本开发之四】

    使用tolua++编译pkg,从而创建自定义类让Lua脚本使用 本站文章均为李华明Himi原创,转载务必在明显处注明:(作者新浪微博:@李华明Himi ) 转载自[黑米GameDev街区] 原文链接: ...

  8. SPI协议介绍

    一.概述 SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在外围设备微控制 ...

  9. CAN协议学习(二)MCAN控制器介绍

    更多细节请参看MCAN2文档mcan2_ps.pdf. 一.MCAN2简介 MCAN2是Mentor公司开发的一个CAN2.0网络控制器的软核,初版2001年末版2006年.MCAN 2控制器实现了B ...

  10. 爬虫的原理获取html中的图片到本地

    如果你想获取哪个网页的图片,如果你想知道那个网址的美女,还等什么.代码走起:下载即可使用 完成这次瞎爬的原理如下: 第一步:获取html内容 * 第二步:然后在获取的html文本中寻找图片,根据htm ...