Java创建线程池的方式

文章目录

  • Java创建线程池的方式
    • 一、通过Executors工厂方法创建
      • 1.Executors.newSingleThreadExecutor()
      • 2.Executors.newFixedThreadPool(n)
      • 3.Executors.newCachedThreadPool()
      • 4. Executors.newScheduledThreadPool(n)
      • 5. Executors.newSingleThreadScheduledExecutor()
      • 6.Executors.newWorkStealingPool():
    • 二、通过Executors工厂创建
      • 1.ThreadPoolExecutor()
    • 三、总结

一、通过Executors工厂方法创建

1.Executors.newSingleThreadExecutor()

解析:这是一个单线程来串行执行所有任务的线程池,保证只有一个线程工作,并且顺序执行任务。堆积任务存放在缓冲队列

构造方法

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

参数解析:

  • corePoolSize: 1 ;核心线程数
  • maximumPoolSize:1;最大线程数
  • keepAliveTime:0L;空闲线程存活的时间
  • TimeUnit:TimeUnit.MILLISECONDS(毫秒);线程存活时间的单位
  • workQueue: new LinkedBlockingQueue<Runnable>();基于链表实现的无界缓冲队列

代码实现

public class SingleThreadExecutorDemo {public static void main(String[] args) {// 创建线程池ExecutorService threadPool = Executors.newSingleThreadExecutor();// 顺序执行任务for (int i = 0; i < 10; i++) {int index = i;threadPool.execute(() -> {System.out.println(index + ": 任务被执行: " + Thread.currentThread().getName());});}}}

执行结果

2.Executors.newFixedThreadPool(n)

解析:这是一个固定线程个数的线程池,只有核心线程。每次提交一个任务就创建一个线程,直到线程数达到线程池的最大大小,其他任务放在缓存队列等待执行。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。FixedThreadPool 多数针对一些很稳定很固定的正规并发线程,多用于服务器。

构造方法

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

参数解析:

  • corePoolSize: nThreads ;核心线程数
  • maximumPoolSize:nThreads;最大线程数
  • keepAliveTime:0L;空闲线程存活的时间
  • TimeUnit:TimeUnit.MILLISECONDS(毫秒);线程存活时间的单位
  • workQueue: new LinkedBlockingQueue<Runnable>();基于链表实现的无界缓冲队列

代码实现

public class FixedThreadPoolDemo {public static void main(String[] args) {// 创建 2 个线程的线程池ExecutorService threadPool = Executors.newFixedThreadPool(2);// 创建任务Runnable runnable = () -> System.out.println("任务被执行,线程:" + Thread.currentThread().getName());// 线程池执行任务(一次添加 8 个任务)threadPool.execute(runnable);threadPool.execute(runnable);threadPool.execute(runnable);threadPool.execute(runnable);threadPool.execute(runnable);threadPool.execute(runnable);threadPool.execute(runnable);threadPool.execute(runnable);}}

执行结果

3.Executors.newCachedThreadPool()

解析:这是一个无界线程池,如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60 秒不执行任务)线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。线程池大小完全依赖于操作系统(或者说 JVM)能够创建的最大线程大小。SynchronousQueue 是一个是缓冲区为 1 的阻塞队列。缓存型池子通常用于执行一些生存期很短的异步型任务,因此在一些面向连接的 daemon 型 SERVER 中用得不多。但对于生存期短的异步任务,它是 Executor 的首选。

构造方法

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

参数解析

  • corePoolSize: 0 ;核心线程数
  • maximumPoolSize:Integer.MAX_VALUE;最大线程数
  • keepAliveTime:60L;空闲线程存活的时间
  • TimeUnit:TimeUnit.SECONDS(秒);线程存活时间的单位
  • workQueue: new SynchronousQueue<Runnable>();缓冲区为1的阻塞队列

代码实现

public class CachedThreadPoolDemo {public static void main(String[] args) {// 创建线程池ExecutorService threadPool = Executors.newCachedThreadPool();// 执行任务for (int i = 0; i < 10; i++) {threadPool.execute(() -> {System.out.println("任务被执行,线程:" + Thread.currentThread().getName());});}
}

}

执行结果

4. Executors.newScheduledThreadPool(n)

解析:这是个核心线程池固定,大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。创建一个周期性执行任务的线程池。如果闲置,非核心线程池会在 DEFAULT_KEEPALIVEMILLIS 时间内回收。

构造方法

public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());
}

参数解析

  • corePoolSize: corePoolSize ;核心线程数
  • maximumPoolSize:Integer.MAX_VALUE;最大线程数
  • keepAliveTime:0L;空闲线程存活的时间
  • TimeUnit:NANOSECONDS(纳秒);线程存活时间的单位
  • workQueue: new DelayedWorkQueue());延时队列

代码实现

public class ScheduledThreadPoolDemo {public static void main(String[] args) {// 创建线程池ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);for (int i = 0; i < 5; i++){// 添加定时执行任务(2s 后执行)System.out.println("添加任务,时间:" + new Date());threadPool.schedule(() -> {System.out.println("任务被执行,时间:" + new Date());}, 2, TimeUnit.SECONDS);}}}

执行结果

5. Executors.newSingleThreadScheduledExecutor()

解析:这是一个单线程的可以执行延迟任务的线程池。这种线程池可以看做是 ScheduledThreadPool 的单线程版本。

构造方法

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {return new DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1));}public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());}

参数解析

  • corePoolSize: 1 ;核心线程数
  • maximumPoolSize:Integer.MAX_VALUE;最大线程数
  • keepAliveTime:0L;空闲线程存活的时间
  • TimeUnit:NANOSECONDS(纳秒);线程存活时间的单位
  • workQueue: new DelayedWorkQueue());延时队列

代码实现

public class SingleThreadScheduledExecutorDemo {public static void main(String[] args) {// 创建线程池ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();// 添加定时执行任务(2s 后执行)System.out.println("添加任务,时间:" + new Date());threadPool.schedule(() -> {System.out.println("任务被执行,时间:" + new Date());try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {}}, 2, TimeUnit.SECONDS);}}

执行结果

6.Executors.newWorkStealingPool():

解析:这是一个抢占式执行的线程池,执行任务的顺序不确定。需要注意的是此方法是 JDK 1.8 版本新增的,所以 1.8 版本之前的程序中不能使用。

构造方法

public static ExecutorService newWorkStealingPool() {return new ForkJoinPool(Runtime.getRuntime().availableProcessors(),ForkJoinPool.defaultForkJoinWorkerThreadFactory,null, true);}

参数解析

  • parallelism: Runtime.getRuntime().availableProcessors(); 是获取当前系统可以的CPU核心数。(可以自定义)

  • ForkJoinWorkerThreadFactory: ForkJoinPool.defaultForkJoinWorkerThreadFactory; 创建新线程的工厂对于默认值,请使用defaultForkJoinWorkerThreadFactory。

  • UncaughtExceptionHandler:null;由于执行任务时遇到不可恢复的错误而终止的内部工作线程的处理程序。对于默认值,请使用null

  • boolean:true; 如果为true,则为从未联接的分叉任务建立本地先进先出调度模式。在工作线程仅处理事件样式异步任务的应用程序中,此模式可能比默认的基于本地堆栈的模式更合适。对于默认值,请使用false。

代码实现

public class WorkStealingPoolDemo {public static void main(String[] args) {// 创建线程池ExecutorService threadPool = Executors.newWorkStealingPool();// 执行任务for (int i = 0; i < 10; i++) {final int index = i;threadPool.execute(() -> {System.out.println(index + " 被执行,线程名:" + Thread.currentThread().getName());});}// 确保任务执行完成while (!threadPool.isTerminated()) {}}}

执行结果

二、通过Executors工厂创建

1.ThreadPoolExecutor()

解析: 这是最原始,也是最推荐的手动创建线程池的方法。创建时支持自定义某些属性,比如核心线程数、最大线程数等。

构造方法

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

参数解析

  • corePoolSize: corePoolSize ;核心线程数
  • maximumPoolSize:maximumPoolSize;最大线程数
  • keepAliveTime:keepAliveTime;空闲线程存活的时间
  • TimeUnit:unit;空闲线程存活时间的单位
  • BlockingQueue: workQueue;线程池所用的队列类型
  • ThreadFactory: threadFactory 线程创建工厂
  • RejectedExecutionHandler: handler corePoolSize已满,队列已满,maxPoolSize 已满,最后的拒绝策略。根据拒绝策略拒绝任务

代码实现

public class ThreadPoolExecutorDemo {public static void main(String[] args) {// 创建线程池ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 10, 100, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10));// 执行任务for (int i = 0; i < 10; i++) {final int index = i;threadPool.execute(() -> {System.out.println(index + " 被执行,线程名:" + Thread.currentThread().getName());});}}}

执行结果

三、总结

线程池工作核心流程

1、先判读当前线程数是否小于 corePoolSize 。如果小于就新建线程执行

2、如果大于,就判断阻塞队列是否已经满了,如果没有满,就加入阻塞队列中。

3、如果满了,就判断当前线程数是否小于 maxPoolSize 。如果小于,就直接创建线程执行。如果大于就根据拒绝策略,拒绝任务。

拒绝策略

线程池有四种拒绝策略

1、丢弃任务,并抛出异常

2、丢弃任务,单不抛出异常

3、丢弃队列最前面的任务,然后重新提交当前任务。

4、线程池什么都不做,由当前线程自己处理。

线程池的关闭:

在调用shutdown() 或者shutdownNow() 之后,线程池并不会立即关闭,会等待所有任务执行完成之后,才会关闭线程池。

shutdown() 不会清空任务队列,并且只会中断空闲线程。

shutdownNow() 会清空任务队列,并且中断所有的线程。

Java创建线程池的方式相关推荐

  1. java创建线程池几种方式_java知识总结-创建线程池的6种方式

    一.创建线程池的6种方式: Executors.newCachedThreadPool(); 创建一个可缓存线程池,应用中存在的线程数可以无限大 Executors.newFixedThreadPoo ...

  2. Java创建线程池的几种方式

    方式一:继承Thread类 新建一个类并该类声明为Thread的子类. 这个子类应该重写run类的方法.例如,计算大于规定值的素数的线程可以写成如下: class PrimeThread extend ...

  3. java创建线程池几种方式_Java 创建线程池两种不同方法的比较

    用Java做抓取的时候免不了要用到多线程的了,因为要同时抓取多个网站或一条线程抓取一个网站的话实在太慢,而且有时一条线程抓取同一个网站的话也比较浪费CPU资源.要用到多线程的等方面,也就免不了对线程的 ...

  4. JAVA 创建线程池

    线程池的作用:      线程池作用就是限制系统中执行线程的数量.      根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果:少了浪费了系统资源,多了造成系统拥挤效率不高.用线程池 ...

  5. java线程池之一:创建线程池的方法

    在Java开发过程中经常需要用到线程,为了减少资源的开销,提高系统性能,Java提供了线程池,即事先创建好线程,如果需要使用从池中取即可,Java中创建线程池有以下的方式, 1.使用ThreadPoo ...

  6. 从源码分析创建线程池的4种方式

    摘要:从创建线程池的源码来深入分析究竟有哪些方式可以创建线程池. 本文分享自华为云社区<[高并发]从源码角度分析创建线程池究竟有哪些方式>,作者:冰 河 . 在Java的高并发领域,线程池 ...

  7. Java多线程学习总结(7)——创建线程池的正确姿势

    一. 通过Executors创建线程池的弊端 在创建线程池的时候,大部分人还是会选择使用Executors去创建. 下面是创建定长线程池(FixedThreadPool)的一个例子,严格来说,当使用如 ...

  8. 为什么阿里不允许用Executors创建线程池,而是通过ThreadPoolExecutor的方式?

    1.通过Executors创建线程池的弊端 在创建线程池的时候,大部分人还是会选择使用Executors去创建. 下面是创建定长线程池(FixedThreadPool)的一个例子,严格来说,当使用如下 ...

  9. 为什么阿里巴巴禁止使用 Executors 创建线程池,而是通过 ThreadPoolExecutor 方式?...

    >>号外:关注"Java精选"公众号,菜单栏->聚合->干货分享,回复关键词领取视频资料.开源项目. 1. 通过Executors创建线程池的弊端 在创建线 ...

最新文章

  1. OpenCV读写视频文件解析
  2. 数据结构学习系列文章合集
  3. 哈佛大学学生保持20个快乐的习惯
  4. 【PDF下载】给专业选手的 Python 笔记
  5. 基于Kubernetes的ESaaS架构及实现细节(二)
  6. 没业绩怎么写好年终总结?这样写总结年终奖翻倍!
  7. android 代码设置像素,【Android实例】用设计原则来重构1像素保活代码
  8. 【转】打印机硬件发现不了解决办法
  9. 带有记忆的菲波那切数列
  10. 用友账套和报表服务器显示不同,用友T3ufo报表提示“服务器出现意外情况”
  11. QQ音乐.qmc3文件转换成正常mp3文件
  12. php李炎恢第二季视频_李炎恢PHP视频教程第二季资源推荐
  13. c语言鸡兔同笼的程序,C语言:鸡兔同笼问题
  14. ecshop批量打印快递单
  15. Android 一个美观简洁的登录界面(一)
  16. 休闲娱乐 - 夏日自制饮料
  17. 拒酒词――――――社交必备
  18. 呼叫中心电话系统,你了解多少?
  19. 多智能体系统编队算法仿真--python3实现
  20. MATLAB设计控制系统仿真实验,基于MATLAB的自动控制原理实验仿真系统的设计

热门文章

  1. [THUWC2017]在美妙的数学王国中畅游 LCT+泰勒展开+求导
  2. OpenGL学习(十)天空盒
  3. C# WinForm创建Excel文件
  4. 西门子S7-1200小练手之电机星三角启动
  5. windows系统下ip地址无法修改,亲测可用imdam博客之家
  6. python a股行情_用Python,tushare做一个A股每日收盘行情监测分析(含源代码)
  7. a73*2+a53*2指的是什么_张露:什么筹什么什么成语
  8. c语言列指针的形式,C语言:行指针和列指针
  9. 蓝桥杯 历届试题 回文日期 C
  10. 简易售货机JAVA sql_JAVA基础---简易自动售货机