介绍:
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。
为什么要使用线程池?
这里借用《Java并发编程的艺术》提到的来说一下使用线程池的好处:

降低资源消耗。 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
提高响应速度。 当任务到达时,任务可以不需要的等到线程创建就能立即执行。
提高线程的可管理性。 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

如何创建线程池?
《阿里巴巴Java开发手册》中强制线程池不允许使用 Executors 去创建,而是通过 new ThreadPoolExecutor 实例的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

使用Executors哪里有风险?有什么风险?
Executors 返回线程池对象的弊端如下:

FixedThreadPool 和 SingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致OOM。

CachedThreadPool 和 ScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致OOM。

下面就分析

分析源码:
先看Executors类,这里先看Executors类调用了哪些方法,至于方法参数的意义,先不用管,后面有详细介绍:
public class Executors {

/*** 创建固定数量线程的线程池** 这是最后一个参数--阻塞队列调用的方法,长度是Integer.MAX_VALUE* public LinkedBlockingQueue() {*    this(Integer.MAX_VALUE);* }** @param nThreads the number of threads in the pool* @return the newly created thread pool* @throws IllegalArgumentException if {@code nThreads <= 0}*/
public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}/*** 创建只有一个线程的线程池** 这是最后一个参数--阻塞队列调用的方法,长度也是Integer.MAX_VALUE* public LinkedBlockingQueue() {*    this(Integer.MAX_VALUE);* }** @return the newly created single-threaded Executor*/
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
}/***创建一个缓冲线程池 ** 这是最后一个参数--阻塞队列调用的方法* public SynchronousQueue() {*    this(false);* }** 它的第二个参数,maximumPoolSize 为Integer.MAX_VALUE** @return the newly created thread pool*/
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}/*** Creates a thread pool that can schedule commands to run after a* given delay, or to execute periodically.** 创建一个可以在给定延迟后再执行或定期执行命令的线程池** ScheduledThreadPoolExecutor 是 ThreadPoolExecutor 的子类,代码如下:*public class ScheduledThreadPoolExecutor extends ThreadPoolExecutorimplements ScheduledExecutorService {//这是下面调用的构造方法,其实是调用了父类的构造方法,这些参数都是下面分析的参数public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());}}** @param corePoolSize the number of threads to keep in the pool,* even if they are idle* @return a newly created scheduled thread pool* @throws IllegalArgumentException if {@code corePoolSize < 0}*/
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);
}

}

可以看到Executors类创建线程池的时候实际就是调用ThreadPoolExecutor类的构造方法来创建。

再看ThreadPoolExecutor类:

public class ThreadPoolExecutor extends AbstractExecutorService {

/**
* 其中一个构造方法:newFixedThreadPool时调用的
*
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default thread factory and rejected execution handler.
* It may be more convenient to use one of the {@link Executors} factory
* methods instead of this general purpose constructor.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @throws IllegalArgumentException if one of the following holds:

* {@code corePoolSize < 0}

* {@code keepAliveTime < 0}

* {@code maximumPoolSize <= 0}

* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}

}

参数介绍:

corePoolSize

在线程池中保持的线程的数量,即使是这些线程没有被使用,除非设置了线程超时时间

maximumPoolSize

最大线程数量,当workQueue队列已满,放不下新的任务,再通过execute添加新的任务则线程池会再创建新的线程,线程数量大于corePoolSize但不会超过maximumPoolSize,如果超过maximumPoolSize,那么会抛出异常,如RejectedExecutionException。

keepAliveTime和unit

当线程池中线程数量大于workQueue,如果一个线程的空闲时间大于keepAliveTime,则该线程会被销毁。unit则是keepAliveTime的时间单位。

workQueue

阻塞队列,当线程池正在运行的线程数量已经达到corePoolSize,那么再通过execute添加新的任务则会被加到workQueue队列中,在队列中排队等待执行,而不会立即执行。

为什么说
FixedThreadPool 和 SingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致OOM。
CachedThreadPool 和 ScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致OOM。
再结合注释看Executors类中的传参就明白了!
Executors中创建线程池:

FixedThreadPool 和 SingleThreadExecutor 传入的最后一个参数阻塞队列 ”workQueue“,默认的长度是INTEGER.MAX_VALUE,而它们允许的最大线程数量又是有限的,所以当请求线程的任务过多线程不够用时,它们会在队列中等待,又因为队列的长度特别长,所以可能会堆积大量的请求,导致OOM。

CachedThreadPool 和 ScheduledThreadPool 它们的阻塞队列长度有限,但是传入的第二个参数maximumPoolSize 为Integer.MAX_VALUE,这就意味着当请求线程的任务过多线程不够而且队列也满了的时候,线程池就会创建新的线程,因为它允许的最大线程数量是相当大的,所以可能会创建大量线程,导致OOM。

下面我们来写个例子看看效果。

public class MyThreadTest implements Runnable,Comparable{

private static ExecutorService executorService=Executors.newFixedThreadPool(100);private static Executor myThread=new ThreadPoolExecutor(100,100,0L, TimeUnit.SECONDS,new PriorityBlockingQueue<Runnable>());
private String name;
public MyThreadTest(String name){this.name=name;
}
public MyThreadTest(){name="";
}@Override
public void run(){try{Thread.sleep(100);System.out.println(name+" running....");}catch(InterruptedException e){e.printStackTrace();}
}
@Override
public int compareTo(MyThreadTest o){int me = Integer.valueOf(name.split("_")[1]);int other = Integer.valueOf(o.name.split("_")[1]);return me-other;
}public static void main(String[] args) {for (int i=0;i<1000;i++){

// myThread.execute(new MyThreadTest(“test_”+(i)));

        executorService.execute(new MyThreadTest("test_"+(i)));}
}

}

test_56 running…
test_39 running…
test_37 running…
test_43 running…
test_57 running…
test_42 running…
test_33 running…
test_15 running…
test_97 running…
test_1 running…
test_74 running…
test_54 running…
。。。
。。。
。。。
test_948 running…
test_943 running…
test_942 running…
test_940 running…
test_941 running…
test_929 running…
test_934 running…
test_932 running…
test_926 running…
test_925 running…
test_923 running…
两者执行效率差不多,如果没有特殊要求建议使用

ExecutorService executorService=Executors.newFixedThreadPool(100);这种方式很简单快捷。如果需要进行其他特殊需求可换成
Executor myThread=new ThreadPoolExecutor(100,100,0L, TimeUnit.SECONDS,new PriorityBlockingQueue());

其中new PriorityBlockingQueue()可以自己定义queue

总结:
Executors类中封装好的创建线程池的方法使用方便,但是也有其局限性和风险性,所以我们可以使用 ThreadPoolExecutor 类中的构造方法手动创建线程池的实例, 从而可以根据我们的使用情况来指定参数,满足使用的同时又能规避风险。

所以,说白了,使用Executors类创建线程池与使用ThreadPoolExecutor类的区别就是使用ThreadPoolExecutor类可以自定义传入我们设置的线程池的参数,更加灵活。

原文:https://blog.csdn.net/SmallCarrot/article/details/85013098
原文:https://blog.csdn.net/qq_36565494/article/details/82802989

executors与threadPoolExecutor区别相关推荐

  1. java线程池案例_使用Executors 和 ThreadPoolExecutor实现Java线程池案例

    并发主题 使用Executors 和 ThreadPoolExecutor实现Java线程池案例 首先需要一个工作线程: package com.journaldev.threadpool; publ ...

  2. Executors和ThreadPoolExecutor详解

    概述 在<阿里巴巴java开发手册>中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量:另一方面线程的细节管理 ...

  3. ThreadPoolTaskExecutor和ThreadPoolExecutor区别

    初学者很容易看错,如果没有看到spring或者JUC源码的人肯定是不太了解的. ThreadPoolTaskExecutor是spring core包中的,而ThreadPoolExecutor是JD ...

  4. java面试高频知识点汇总 2021-02-24

    杂碎知识点1 大四开始找工作后遇到的面试题进行汇总,因为之前记录的都是在有道云中,复制到简书出现格式的问题,大致修补了一下,后续继续上传. 1.Integer缓存池问题 当给Integer赋值在-12 ...

  5. java 阿里线程池_为什么阿里不允许使用 Executors 创建线程池?

    你知道为什么阿里不允许Executors去创建线程池吗? 阿里巴巴开发手册关于线程池有这样一条规定: 线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方 ...

  6. java_多线程——线程池、submit和execute区别

    一.线程池的概念 顾名思义就是事先准备一个池子(线程池),初始化一些线程,当使用可以快速调用,不用再初始化线程,使用完成后,不再销毁该线程,归还到线程池,方便后面复用.节省创建和销毁线程资源,提高线程 ...

  7. 使用执行程序和ThreadPoolExecutor的Java线程池示例

    线程池管理工作线程池,它包含一个队列,使任务等待执行. 线程池管理可运行线程的集合,工作线程从队列中执行可运行线程. java.util.concurrent.Executors提供java.util ...

  8. inputstreamreader未关闭会导致oom_【搞定面试官】你还在用Executors来创建线程池?会有什么问题呢?

    前言 上文我们介绍了JDK中的线程池框架Executor.我们知道,只要需要创建线程的情况下,即使是在单线程模式下,我们也要尽量使用Executor.即: ExecutorService fixedT ...

  9. 线程池源码分析之ThreadPoolExecutor

    前言 今天老吕给大家来分享下ThreadPoolExecutor 线程池的实现逻辑,大家伙认真看,一般人我不告诉他的. 线程池相关类图 JDK中线程池相关的类结构关系图 获取不同特性的线程池 在Exe ...

最新文章

  1. 单击“登录”后,用户名和密码显示在地址栏中,不安全
  2. linux系统空间不足,lsof看到异常的delete状态的文件。
  3. 零日漏洞迟迟未补上:扫描发现超85万思科设备受影响
  4. stm32编译时报错 ..........ER_IROM1: File exists 的问题
  5. JZOJ 5435. 【NOIP2017提高A组集训10.30】Graph
  6. 【最新合集】PAT乙级最优题解(题解+解析+代码)
  7. DDIA笔记—第六章 数据分区
  8. github创建一个新的tag
  9. 极速pdf编辑器的水印如何去掉_如何修改PDF?有没有详细的PDF编辑器操作方法?...
  10. spring集成 log4j + slf4j
  11. android开机动画修改,Android系统 开机动画修改 + 自动替换脚本
  12. js 中断函数执行_js如何中断递归函数
  13. 有关Spring中Resource的继承关系(代码解读)
  14. ARM开发7.5.1 基础实训( 5 ) 4×4 矩阵键盘和 2 路 LED 显示系统( 1)--LPC21XX
  15. Line-in和Mic-in的区别和使用及Line-out
  16. Learning Deep Structured Semantic Models for Web Search using Clickthrough Data
  17. 基于微信小程序的家教信息管理系统毕业设计源码
  18. react 调用webIm
  19. Golang panic: reflect: reflect.flag.mustBeAssignable using value obtained using unexported field
  20. C++ Primer Plus习题及答案-第五章

热门文章

  1. 【C语言】动手写一个哈希表
  2. Substance Painter 服饰材质制作 - 肩带1
  3. 作为软件测试人员,这些常用的性能测试工具你一定要知道
  4. 项目开发中,真的有必要定义VO,BO,PO,DO,DTO这些吗?
  5. python pip、conda、windows CMD常用命令大全!
  6. 【小技巧】IDEA更换个性自定义背景
  7. 为什么现在的游戏越来越不好玩了?
  8. 用微软Custom Version识别水果:三分钟开发人工智能小应用
  9. 【攻防世界 level2】
  10. 用MATLAB作微粉环节,电力系统分析理论课本习题MATLAB做.doc