一、Executor框架介绍

Executor框架将Java多线程程序分解成若干个任务,将这些任务分配给若干个线程来处理,并得到任务的结果

1.1、Executor框架组成

任务:被执行任务需要实现的接口:Runnable接口或Callable接口

任务的执行:任务执行的核心接口Executor以及其子类ExecutorService接口

任务的结果:包括Future接口以及Future接口的实现类FutureTask类

Executor接口是Executor框架的基础,将任务的提交与执行分离开

ThreadPoolExecutor:线程池核心实现类,用来执行提交的任务

ScheduledThreadPoolExecutor:在给定的延迟时间后执行或定期执行任务,相当于ThreadPoolExecutor的定时器版本

Future接口和实现类FutureTask代表异步处理的结果

Runnable接口和Callable接口都是当做任务被ThreadPoolExecutor和ScheduledThreadPoolExecutor来执行

二、ThreadPoolExecutor详解

ThreadPoolExecutor通常可以使用工厂类Executors来创建,可以有以下三种类型:

SingleThreadExecutor:单线程线程池执行器,适用于需要保证顺序地执行各个任务且不会出现多线程同时活动的情况

FixedThreadPool:创建使用固定线程数量的线程池,可以限制当前线程数量,比较常用。

CachedThreadPool:大小无界的线程池,适用于需要执行大量短期异步任务的场景或者是服务器负载较小的情况

2.1、FixedThreadPool详解

源码如下:

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

可以看出只需要设置两个参数:线程数量和线程工厂(可不传)

1.这里可以看出FixedThreadPool使用的工作队列是无界的链表结构的阻塞队列,所以这里的maximumPoolSize参数就设置成了和coolPoolSize一样的值,因为设置再大也失去了意义;

2.多余线程保持活跃的时间设置成了0,也就是多余的空闲线程会立即终止;

3.由于队列是无界的,所以线程池不会出现拒绝任务的情况,所以也不会用到饱和策略;

4.整体的工作流程就是:

线程池中线程数量少于corePoolSize时会先创建新线程来预热,达到之后就将任务放入LinkedBlockingQueue队列中,线程执行完任务之后会循环从队列中获取任务来执行

2.2、SingleThreadExecutor详解

源码如下:

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

可以看出SingleThreadExecutor和FixedThreadPool几乎一样,只是线程只会有一个线程,相比于FixedThreadPool的好处就是可以保证任务的顺序性

2.3、CachedThreadPool详解

源码如下:

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

可以看出也只需要设置线程工厂一个参数,而其他参数都是固定的,corePoolSize设置为0,即corePool为空;maximumPoolSize设置为了Integer的最大值就表示是无大小限制了。keepAliveTime设置成了60秒;队列使用了SynchronousQueue

整体的工作流程为:

1.提交任务到SynchronousQueue队列中,如果线程池中有空余的线程在执行poll操作,则此任务就会被该线程获取执行

2.如果线程池中没有空闲线程,则就会在线程池中创建新的线程来执行poll操作获取任务

3.线程池中的空闲线程如果poll操作没有获取到任务,则会等待60秒,如果没有等待任务则线程终止

所以CachedThreadPool的好处是没有任务的时候,线程池中不需要创建线程等待任务,或者任务执行完之后,线程会在不久就会释放,节省了资源。但是如果任务数量较大,且线程处理任务的速度慢于主线程提交任务的速度,那么线程池中就会不停的创建新线程来执行,

就会有线程数量过多而导致CPU和内存资源被消耗尽的情况

三、FutureTask详解

3.1、FutureTask用法

FutureTask除了实现了Future接口,还实现了Runnable接口,所以FutureTask可以被Executor执行,也可以直接调用本身的run方法执行。

FutureTask有三种状态:未启动(未执行run方法)、已启动(执行run方法中)、已结束(run方法结束或抛出异常)

当FutureTask不是处于已结束状态时,调用get方法会阻塞当前线程知道任务结束;当处于已结束状态时,调用get方法会返回任务执行的结果或抛出对应的异常

当FutureTask处于未启动状态时,调用cancel方法会导致该任务永远不会被执行;

当FutureTask处于已启动状态时,调用cancel(true)方法会中断执行的任务,调用cancel(false)方法将不会对正在执行此任务的线程产生影响

当FutureTask处于已结束状态时,调用cancel方法会返回false

3.2、FutureTask实现原理

FutureTask底层是基于AQS(抽象同步队列)实现的

深入浅出JAVA线程池使用原理2的更多相关文章

  1. 深入浅出JAVA线程池使用原理1

    前言: Java中的线程池是并发框架中运用最多的,几乎所有需要异步或并发执行任务的程序都可以使用线程池,线程池主要有三个好处: 1.降低资源消耗:可以重复使用已经创建的线程降低线程创建和销毁带来的消耗 ...

  2. 深入浅出Java线程池:源码篇

    前言 在上一篇文章深入浅出Java线程池:理论篇中,已经介绍了什么是线程池以及基本的使用.(本来写作的思路是使用篇,但经网友建议后,感觉改为理论篇会更加合适).本文则深入线程池的源码,主要是介绍Thr ...

  3. Java线程池的原理及几类线程池的介绍

    刚刚研究了一下线程池,如果有不足之处,请大家不吝赐教,大家共同学习.共同交流. 在什么情况下使用线程池? 单个任务处理的时间比较短 将需处理的任务的数量大 使用线程池的好处: 减少在创建和销毁线程上所 ...

  4. 并发编程(十二)—— Java 线程池 实现原理与源码深度解析 之 submit 方法 (二)

    在上一篇<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.这篇文章是接着上一篇文章 ...

  5. Java 线程池的原理与实现 (转)

        最近在学习线程池.内存控制等关于提高程序运行性能方面的编程技术,在网上看到有一哥们写得不错,故和大家一起分享. [分享]Java 线程池的原理与实现 这几天主要是狂看源程序,在弥补了一些以前知 ...

  6. Java线程池实现原理及其在美团业务中的实践

    本文转载自Java线程池实现原理及其在美团业务中的实践 导语 随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流.使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器.J.U.C提供 ...

  7. 我眼中的java线程池实现原理

    最近在看java线程池实现方面的源码,在此做个小结,因为网上关于线程池源码分析的博客挺多的,我也不打算重复造轮子啦,仅仅用纯语言描述的方式做做总结啦! 个人认为要想理解清楚java线程池实现原理,明白 ...

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

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

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

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

随机推荐

  1. mysql 表分区技术

    表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分.从逻辑上看,只有一张表,但是底层却是由多个物理分区组成. 表分区有什么好处: a.分区表的数据可以分布在不同的物理设备上, ...

  2. ELK日志收集

    目前日志的痛点 运维要经常登陆到服务器上拿日志给开发.测试 每次都是出问题后才去看日志,不能提前通过日志预判问题 如果是集群服务,日志将要从多台机器取 开发人员搞出来的日志不规范,没有标准.日志目录不 ...

  3. redis数据操作笔记

    redis是key-value的数据结构,每条数据都是一个键值对键的类型是字符串 注意:键不能重复,值的类型分为五种:字符串string 哈希hash 列表list 集合set 有序集合zset 一. ...

  4. win PowerCmd命令行工具安装

    官网:http://www.powercmd.com/ 下载地址:http://www.powercmd.com/Install_PowerCmd.exe 版本信息: 输入注册码: PowerCmd ...

  5. MakeFile 详解

    最近在学习Linux下的C编程,买了一本叫<Linux环境下的C编程指南>读到makefile就越看越迷糊,可能是我的理解能不行. 于是google到了以下这篇文章.通俗易懂.然后把它贴出 ...

  6. ef报错:实体类型XXX不是当前上下文的模型的一部分。

    可能原因:.net框架版本与实体框架版本不匹配,比如:.net框架版本为4.5.实体框架版本为6.2. 解决方法:将实体框架版本降到6.0.

  7. php操作redis案例

    <?php     //实例化     $redis = new Redis();     //连接服务器     //默认端口是6379,可不写     $redis->connect( ...

  8. php框架中,try,catch不能用的问题(转载)

    本文转自:http://blog.csdn.net/sangjinchao/article/details/71436557 最近再用laravel框架发现,try catch用了没有效果,依然不能阻 ...

  9. ThinkPHP缓存技术(S(),F(),查询缓存,静态缓存)

    直接查看原网址 https://blog.csdn.net/u010081689/article/details/47976271

  10. 细说一下position(定位),以及其他的小知识

    细说:position      位置 1.只要使用定位,必须要有一个相对的参照物.relative 2.具体定位的那个1元素需要加position:absolute:绝对的 绝对的:就是具体到某一个 ...