概述

在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用Executors去创建,而要通过ThreadPoolExecutor方式,这一方面是由于jdk中Executor框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险

1、线程池的七种创建方式

Executors 创建的六种

  1. Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;
  2. Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程;
  3. Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序;
  4. Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池;
  5. Executors.newSingleThreadScheduledExecutor:创建一个单线程的可以执行延迟任务的线程池;
  6. Executors.newWorkStealingPool:创建一个抢占式执行的线程池(任务执行顺序不确定)【JDK 1.8 添加】

示例:

ExecutorService executorService = Executors.newFixedThreadPool(3);

ThreadPoolExecutor 创建的一种(ThreadPoolExecutor:最原始的创建线程池的方式,它包含了 7 个参数可供设置)

ThreadPoolExecutor提供了四个构造方法:

    public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {}public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {}public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {}public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {}

参数详解:

    public ThreadPoolExecutor(int corePoolSize, //核心线程数,线程池中始终存活的线程数int maximumPoolSize, //最大线程数,线程池中允许的最大线程数long keepAliveTime, //最大线程数可以存活的时间TimeUnit unit, //时间单位BlockingQueue<Runnable> workQueue, //阻塞队列,workQueue包含七种ThreadFactory threadFactory, //线程工厂,主要用来创建线程RejectedExecutionHandler handler //拒绝策略) {super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);this.prestartAllCoreThreads();}

实例:

    private static ExecutorService executorService;public static void main( String[] args ) {executorService = new ThreadPoolExecutor(2, 4, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5),new ThreadFactory() {public Thread newThread(Runnable runnable) {log.info("创建线程:{}",runnable.hashCode());Thread threadName = new Thread(runnable,"threadPool"+runnable.hashCode());return threadName;}}, new ThreadPoolExecutor.CallerRunsPolicy());// ThreadTask类实现Runnable接口,这里省略了executorService.execute(new ThreadTask());}

ThreadPoolExecutor执行原理概述

点击executorService.execute(new ThreadTask())的execute()方法
public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();// 1、工作线程 < 核心线程 if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}// 2、运行态,并尝试将任务加入队列if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();if (! isRunning(recheck) && remove(command))reject(command);else if (workerCountOf(recheck) == 0)addWorker(null, false);} // 3、使用尝试使用最大线程运行else if (!addWorker(command, false))reject(command);}

这三处if判断,还是比较泛的,整体大框框上的流程,可用下图表示:

上述代码中的三种传参方式:

  1. addWorker(command, true): 创建核心线程执行任务;
  2. addWorker(command, false):创建非核心线程执行任务;
  3. addWorker(null, false): 创建非核心线程,当前任务为空;

     addWorker的工作可分为两个部分:

  • 第一部分:原子操作,判断是否可以创建worker。通过自旋、CAS、ctl 等操作,判断继续创建还是返回false,自旋周期一般很短。
  • 第二部分:同步创建workder,并启动线程。

ThreadPoolExecutor的执行主要围绕Worker,Worker 实现了 AbstractQueuedSynchronizer 并继承了 Runnable

ExecutorService转换为ThreadPoolExecutor获取当前活动线程数

    public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(3);// 获取当前活动线程数int activeCount = ((ThreadPoolExecutor) executorService).getActiveCount();}

ThreadPoolExecutor常用方法:

Modifier and Type

Method and Description
protected void afterExecute(Runnable r, Throwable t)

完成指定Runnable的执行后调用方法。

void allowCoreThreadTimeOut(boolean value)

设置策略是否核心线程可能会超时,如果任务没有在活着的时间内到达,则在新任务到达时被替换。

boolean allowsCoreThreadTimeOut()

如果此池允许核心线程超时并终止,如果没有任务在keepAlive时间内到达,则返回true,如果新任务到达时需要更换。

boolean awaitTermination(long timeout, TimeUnit unit)

阻止所有任务在关闭请求完成后执行,或发生超时,或当前线程中断,以先到者为准。

protected void beforeExecute(Thread t, Runnable r)

在给定的线程中执行给定的Runnable之前调用方法。

void execute(Runnable command)

在将来某个时候执行给定的任务。

protected void finalize()

当这个执行器不再被引用并且没有线程时,调用 shutdown 。

int getActiveCount()

返回正在执行任务的线程的大概数量。

long getCompletedTaskCount()

返回完成执行的任务的大致总数。

int getCorePoolSize()

返回核心线程数。

long getKeepAliveTime(TimeUnit unit)

返回线程保持活动时间,这是超过核心池大小的线程在终止之前可能保持空闲的时间量。

int getLargestPoolSize()

返回在池中同时进行的最大线程数。

int getMaximumPoolSize()

返回允许的最大线程数。

int getPoolSize()

返回池中当前的线程数。

BlockingQueue<Runnable> getQueue()

返回此执行程序使用的任务队列。

RejectedExecutionHandler getRejectedExecutionHandler()

返回不可执行任务的当前处理程序。

long getTaskCount()

返回计划执行的任务的大概总数。

ThreadFactory getThreadFactory()

返回用于创建新线程的线程工厂。

boolean isShutdown()

如果此执行者已关闭,则返回 true 。

boolean isTerminated()

如果所有任务在关闭后完成,则返回 true 。

boolean isTerminating()

如果此执行者在 shutdown()或 shutdownNow()之后 终止 ,但尚未完全终止,则返回true。

int prestartAllCoreThreads()

启动所有核心线程,导致他们等待工作。

boolean prestartCoreThread()

启动核心线程,使其无法等待工作。

void purge()

尝试从工作队列中删除已取消的所有Future任务。

boolean remove(Runnable task)

如果此任务存在,则从执行程序的内部队列中删除此任务,从而导致该任务尚未运行。

void setCorePoolSize(int corePoolSize)

设置核心线程数。

void setKeepAliveTime(long time, TimeUnit unit)

设置线程在终止之前可能保持空闲的时间限制。

void setMaximumPoolSize(int maximumPoolSize)

设置允许的最大线程数。

void setRejectedExecutionHandler(RejectedExecutionHandler handler)

为不可执行的任务设置一个新的处理程序。

void setThreadFactory(ThreadFactory threadFactory)

设置用于创建新线程的线程工厂。

void shutdown()

启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务。

List<Runnable> shutdownNow()

尝试停止所有主动执行的任务,停止等待任务的处理,并返回正在等待执行的任务列表。

protected void terminated()

执行程序已终止时调用方法。

String toString()

返回标识此池的字符串及其状态,包括运行状态和估计的工作人员和任务计数的指示。

查询文档  Java 8 中文版 - 在线API中文手册

Executors和ThreadPoolExecutor详解相关推荐

  1. ThreadPoolExecutor详解及线程池优化

    前言 ThreadPoolExecutor在concurrent包下,是我们最常用的类之一.无论是做大数据的,还是写业务开发,对其透彻的理解以及如何发挥更好的性能,成为了我们在更好的coding道路上 ...

  2. 多线程之ThreadPoolExecutor详解

    一.为什么使用ThreadPoolExecutor来创建线程池 线程资源必须通过线程池提供,不允许在应用中自行显式创建线程. 因为线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解 ...

  3. 线程池ThreadPoolExecutor详解(整理详细)

    ThreadPoolExecutor 1.什么是线程池? (首先要理解什么是线程) 线程池,thread pool,是一种线程使用模式,线程池维护着多个线程,等待着监督管理者分配可并发执行的任务. 通 ...

  4. java threadpoolexecutor 返回值_Java ThreadPoolExecutor详解

    ThreadPoolExecutor是Java语言对于线程池的实现.池化技术是一种复用资源,减少开销的技术.线程是操作系统的资源,线程的创建与调度由操作系统负责,线程的创建与调度都要耗费大量的资源,其 ...

  5. Java常用四大线程池用法以及ThreadPoolExecutor详解

    2019独角兽企业重金招聘Python工程师标准>>> 为什么用线程池? 1.创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处-理效率 2.线程并发数量过多 ...

  6. 【java】之常用四大线程池用法以及ThreadPoolExecutor详解

    为什么用线程池? 1.创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处-理效率 2.线程并发数量过多,抢占系统资源从而导致阻塞 3.对线程进行一些简单的管理 在Java中,线 ...

  7. 线程池(ThreadPoolExecutor)详解

    线程池 线程池 线程池种类: ThreadPoolExecuter 类关系 结构 自定义线程池参数: 线程池的大小(maximumPoolSize): JDK提供的线程池 singleThreadPo ...

  8. Executors线程池详解(全)

    开场白 构造一个线程池为什么需要几个参数?如果避免线程池出现OOM? Runnable 和 Callable 的区别是什么?本文将对这些问题一一解答,同时还将给出使用线程池的常见场景和代码片段. 基础 ...

  9. ThreadPoolExecutor详解

    一.ThreadPoolExecutor类讲解 1.线程池状态: 五种状态: 线程池 的状态 说明 RUNNING 允许提交并处理任务 SHUTDOWN 不允许提交新的任务,但是会处理完已提交的任务 ...

最新文章

  1. C++:求极值的 min_element、max_element和minmax_element算法
  2. python新手程序员工资-程序员吐槽新同事:连我实习水平都不到,工资是我的1.7倍...
  3. ipqc异常处理流程图_IPQC巡检流程.七大手法.八大原则.九大步骤
  4. v8声卡调音软件_声卡出现杂音怎么办?教你几招解决杂音问题
  5. 阿里成立智能搜索业务部;任天堂:共有30万账号被黑客入侵;TiDB 3.1.2 发布| 极客头条...
  6. 如何在自己开发的android应用中添加广告
  7. 使用C#开发纽曼USB来电小秘书客户端小结
  8. 接口自动化测试框架搭建(6、对接口进行mock的方法封装)--python+HTMLTestRunnerCN+request+unittest+mock+db
  9. 基础集合论 第一章 2 集合
  10. 编程之道 The Tao Of Programming
  11. Android低功耗蓝牙通讯
  12. OpenCV-Python教程:图像金字塔
  13. 硬盘录像机常见问题解答硬盘录像机故障解决
  14. log4cxx linux 使用,log4cxx在Linux下的编译使用
  15. Linux下rsync安装与配置
  16. 隔行换色并且鼠标指向行变色的表格
  17. 【项目实战】C/C++轻松实现4399小游戏:围住神经猫
  18. iOS APP上线流程规范
  19. 【纸牌屋】第一季第二集经典台词
  20. sparql rdf_使用SPARQL查询RDF数据

热门文章

  1. golang第三方库Excelize
  2. Matlab自相关/互相关函数xcorr
  3. 前端私服 + vue(nexus3配置npm私有仓库)-----已解决
  4. 【gitee代码图形化提交(小乌龟)】
  5. 查看期刊分区及影响因子
  6. 渗透测试信息收集之域名信息、子域名信息、IP信息、端口信息
  7. MATLAB 三维图 分类图例
  8. 传阿里云盘将开启扩容收费测试:200GB售价 108元/年;偷车贼使用苹果 AirTag 追踪想要盗走的高档汽车;Visual Studio 2022和 .NET 6正式版本发布|极客头条
  9. Uncaught (in promise) error问题排查
  10. 深度强化学习 | 用TensorFlow构建你的第一个游戏AI