一、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. dubbo RPC超时异常小结

    dubbo消费者调用服务超时的原因可能有很多,今天排查问题花了两个小时,也查了很多资料,好像每一篇资料都是提出一个问题,所以简单总结几点: 1. 配置才是重中之重,仔细检查服务提供方的dubbo se ...

  2. classmethod作用

    >>> class A(object): bar = 1 def func1(self): print 'foo' >>> class A(object): bar ...

  3. nginx相关知识

    一.负载均衡与反向代理 server { listen 9008; server_name localhost; location / { proxy_pass http://web_server; ...

  4. iOS - UITableView reloadData滚动到顶部无效问题解决

    //tableView:动态cell的高度不固定,滑动不到最顶部 //if (self.sensorDate.count > 0) { // [self.tableView scrollToRo ...

  5. K XOR Clique

    BaoBao has a sequence a​1​,a​2,...,a​n. He would like to find a subset S of {1,2,...,n} such that ∀i ...

  6. Retrofit2 项目配置

    在项目的 app  build.gradle 文件中加入 dependencies { // Retrofit2implementation 'com.squareup.retrofit2:retro ...

  7. java实现爬虫功能

    /** * 爬取新闻信息,封装成实体bean */public class GetNews { public List<News> getNews() {  // 存储新闻对象  List ...

  8. json转换学习

    文章部分代码实体类可以忽略. 原文:https://www.cnblogs.com/free-dom/p/5801866.html 代码如下: package covert; import java. ...

  9. js判断PC端还是移动端

    function goPAGE() { if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobi ...

  10. 【zc】 php计算两个日期相隔多少年,多少月,多少日的函数

    /* *function:计算两个日期相隔多少年,多少月,多少天 *数据接受格式: '2014-12-03','2000-12-01'; *param string $date1[格式如:2011-1 ...