ThreadPoolExecutor

简述:

  有的时候,系统处理很多任务,如何这些任务要是都是通过new Thread来做的话,系统就不得不常常的创建之后还要销毁Thread,这个是非常消耗时间而且还占用资源,所以我们通过创建线程池来管理我们的线程。

ThreadPoolExecutor:

  我们是首先来看一下他的构造函数,并且讲解一下里面参数的意思

    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}
复制代码
  • corePoolSize   核心线程数。当我们向线程池中提交新的任务的时候,线程池会创建一个新的线程来执行这个任务,直到线程数等于corePoolSize,默认情况下核心线程会一直存活下去的。
  • maximumPoolSize   最大线程数。要是阻塞队列满了的话,继续添加新的线程的话,并且当前线程小于maximumPoolSize,那么就会创建新的线程来执行这个任务
  • keepAliveTime   线程允许空闲状态存活的时间,前提是此线程不是核心线程。
  • unit   这个参数是keepAliveTime的时间的单位,例如MICROSECONDS,SECONDS,MINUTES等等
  • workQueue   阻塞队列。用来存储等待执行的任务的阻塞队列,系统给我们提供了一下几个阻塞队列:ArrayBlockingQueue,LinkedBlockingQuene,SynchronousQuene和priorityBlockingQuene(我们在后面会讲到)
  • threadFactory   线程工厂。默认的是DefaultThreadFactory,里面定义了线程计数,线程命名规则。当然这些我们都可以自定义。
  • handler   饱和策略。我们可以实现RejectedExecutionHandler重写rejectedExecution方法来自定义,当然系统也给我们提供了几个:AbortPolicy, DiscardPolicy,DiscardOldestPolicy,CallerRunsPolicy(我们在后面也会讲到)

  我们前面笼统的提到了很多概念我猜测很多人现在都不太懂,那我们一点一点的来深入吧。

BlockingQueue

  BlockingQueue接口继承了Queue接口,里面有比较重要的几个方法,分别是offer方法,poll方法,普通方法,take方法,我们看看他的区别:

----抛出异常特殊值阻塞超时
插入add(e)offer(e)put(e)offer(e.time,unit)
移除remove()poll()take()poll(time,unit)
检查element()peek()不可用不可用

add方法会在插入数据时,插入失败就会抛异常,offer会在插入失败时返回false,put方法会在当队列存储对象达到限定值阻塞线程,而在队列不为空的时唤醒被take方法所阻塞的线程。

常见BlockingQueue的实现

  • ArrayBlockingQueue

  他是一个底层是由数组实现的有界的FIFO(先进先出)的阻塞队列。我们看一下他的构造函数

  public ArrayBlockingQueue(int capacity, boolean fair) {if (capacity <= 0)throw new IllegalArgumentException();this.items = new Object[capacity];lock = new ReentrantLock(fair);notEmpty = lock.newCondition();notFull =  lock.newCondition();}
复制代码

  参数1:指定queue的capacity(容量),并且一旦设定则无法更改.   参数2:一个默认是false的bool值,指的是创建的是不是公平锁,如果为true,则按照 FIFO 顺序访问插入或移除时受阻塞线程的队列;如果为 false,则访问顺序是不确定的

 public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}复制代码
  • LinkedBlockingQueue

  一个基于链表的阻塞队列,他的内部维持着一个链表队列用于存储。他的容量也是有固定大小的,如果不设置的情况下默认值是Integer.MAX_VALUE,他之所以能够高效的处理高并发的数据。是因为他的采用了两个独立的锁来控制数据同步

    /** Lock held by take, poll, etc */private final ReentrantLock takeLock = new ReentrantLock();/** Wait queue for waiting takes */private final Condition notEmpty = takeLock.newCondition();/** Lock held by put, offer, etc */private final ReentrantLock putLock = new ReentrantLock();/** Wait queue for waiting puts */private final Condition notFull = putLock.newCondition();
复制代码
  • PriorityBlockingQueue   一个基于优先级的队列。他的优先级通过构造函数传入的Compator对象来决定,当时这个队列并不会阻塞数据的生产者,当数据队列中没有可消费的数据的时候,会阻塞消费者。那么我们就需要注意生成者的生成数据的速率不能高于消费速率,不然会消耗可用的堆内存。

  • SynchronousQueue   这个队列的神奇之处在于它内部没有容器,什么意思呢,就是当你的生产线程(put)成产啦,如果没有消费者消费(take),那么此生产线程就会被阻塞,知道有消费者调用take的时候。反过来先take等待put也是同理

ThreadFactory

  ThreadFactory接口里面的内容很简单,我们看一下源码

public interface ThreadFactory {/*** Constructs a new {@code Thread}.  Implementations may also initialize* priority, name, daemon status, {@code ThreadGroup}, etc.** @param r a runnable to be executed by new thread instance* @return constructed thread, or {@code null} if the request to*         create a thread is rejected*/Thread newThread(Runnable r);
}
复制代码

  他的实现也是非常简单,只需要我们重写里面的newThread方法返回一个Thread就可以啦,我们可以在里面设置我们自己的命名格式等等。那我们先看看JDK中的默认实现DefaultThreadFactory:

    /*** The default thread factory.*/private static class DefaultThreadFactory implements ThreadFactory {private static final AtomicInteger poolNumber = new AtomicInteger(1);private final ThreadGroup group;private final AtomicInteger threadNumber = new AtomicInteger(1);private final String namePrefix;DefaultThreadFactory() {SecurityManager s = System.getSecurityManager();group = (s != null) ? s.getThreadGroup() :Thread.currentThread().getThreadGroup();namePrefix = "pool-" +poolNumber.getAndIncrement() +"-thread-";}public Thread newThread(Runnable r) {Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(),0);//创建生成线程的名字if (t.isDaemon())t.setDaemon(false);if (t.getPriority() != Thread.NORM_PRIORITY)t.setPriority(Thread.NORM_PRIORITY);return t;}}
复制代码

handler

  既然要说这个饱和策略那就先说一个任务是怎么被添加的吧!.一个新的任务通过 execute(Runnable) 方法被添加到线程池,任务就是一个 Runnable 类型的对象,任务的执行方法就是 Runnable 类型对象的 run() 方法。那么当一个任务通过 execute(Runnable) 方法欲添加到线程池时,线程池采用的策略如下:

**1. 当线程池中的数量小于corePoolSize的时候,即使你的线程池中的线程都处于空闲状态,也要开启一个新的线程来处理新的任务。

  • 当你线程池的数量等于corePoolSize的时候,且你的BlockQueue队列没有满的时候,那么任务被加入缓冲队列。
  • 当你的线程池的数量大于corePoolSize的时候,并且你的BlockQueue队列满的时候,但是线程池的数量小于maximumPoolSize的时候,会创建新的线程处理新的任务。
  • 当你的线程池的数量大于corePoolSize的时候,并且你的BlockQueue队列满的时候,但是线程池的数量等于maximumPoolSize的时候,我们的handler出场啦,就有这个饱和策略来处理新的任务**

  我们有四种饱和模式

  • ThreadPoolExecutor.AbortPolicy()     对拒绝任务执行抛弃处理,并且抛出异常
  • ThreadPoolExecutor.CallerRunsPolicy      这个策略重试添加当前的任务,他会自动重复调用 execute() 方法,直到成功
  • ThreadPoolExecutor.DiscardOldestPolicy()     对拒绝任务不抛弃,而是抛弃队列里面等待最久的一个线程,然后把拒绝任务加到队列
  • ThreadPoolExecutor.DiscardPolicy     对拒绝任务直接无声抛弃,没有异常信息。

ThreadPoolExecutor的使用

  小伙伴在看完之后肯定觉得线程池使用起来有点麻烦,难道就没有现成的让我们使用吗?当然有啦,好东西都是留在最后的吗!

  • newFixedThreadPool   固定大小的线程池,根据参数来决定生成的核心线程数量和最大线程数量,内部使用的是LinkedBlockingQueue
    public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}
复制代码
  • newCachedThreadPool   可缓存的线程池,因为内部使用的是SynchronousQueue队列,由于核心线程数为0,最大线程是为Integer.MAX_VALUE,可以让他灵活回收空闲线程,若无可回收,则新建线程。
   public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}复制代码
  • newScheduledThreadPool   根据参数来生成一个定长的线程池,由于使用的是DelayedWorkQueue,这个我们在前面没有介绍,在这里简单的说一下 他是一个无界阻塞队列,只有在延迟期满时才能从中提取元素,那么就可以用来做延迟操作或者周期性的操作啦
  public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);}public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue());}
复制代码
  • newSingleThreadExecutor   他的核心线程数还有最大线程数都是1,又由于用的是LinkedBlockingQueue无参数构造,那就是默认的Integer.MAX_VALUE的个数的阻塞队列,换句话说就是这里会一个一个安装指定顺序执行任务
    public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}
复制代码

  当然除了这些还有好多自带呢不在一一说明,希望读者能够自己带着感悟去看源码,将会有跟深层次的理解!

转载于:https://juejin.im/post/5addbce2f265da0ba062c5bb

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283480.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

你总说时间很少

你总说时间很少 没时间看哭泣的骆驼 少了心情 你总说时间很少 没时间撩拨那爱的罗曼史 少了喜欢 你总说时间很少 没时间吮吸印度洋的水清沙白 少了勇敢 你总说时间很少 没时间寻找相伴的野马 少了感觉 可到最后 时间真的很少 有了喜欢 就少了心情 有了感觉 就少了勇敢…

Unity 将是驱动 C# 增长的引擎吗 ?

C# 在中国的采用需要一个杀手级应用的带动&#xff0c; 那么这样的一个杀手级应用是 Unity吗&#xff0c;我这里大胆推测采用CoreCLR 的新一代完全采用C#构建的Unity 将是这样的一个杀手级应用。Unity已被广泛应用于数字孪生、数字城市、数字工厂等场景&#xff0c;成为各产业加…

HTML5video 标签

属性 值 说明 autoplay autoplay 如果出现该属性&#xff0c;则视频在就绪后马上播放。 controls controls 如果出现该属性&#xff0c;则向用户显示控件&#xff0c;比如播放按钮。 preload preload 如果出现该属性&#xff0c;则视频…

Windows 超级开源实用工具:Microsoft PowerToys

实用工具集&#xff1a; Always on Top ​通过 Always on Top&#xff0c;可使用快捷键方式 (⊞ WinCtrlT) 将窗口固定在其他窗口的顶部。 ​ PowerToys Awake PowerToys Awake旨在使计算机保持唤醒状态&#xff0c;且无需管理其电源和睡眠设置。 运行耗时较长的任务时&#…

Python入门之数据类型

字符串 列表 元组 字典 转载于:https://www.cnblogs.com/py17/p/8919495.html

Kubeadm 快速搭建 k8s v1.24.1 集群(openEuler 22.03 LTS)

kubeadm 简介kubeadm 是 Kubernetes&#xff08;以下简称 k8s&#xff09;官方提供的用于快速安装部署 k8s 集群的工具&#xff0c;伴随 k8s 每个版本的发布都会同步更新&#xff0c;kubeadm 会对集群配置方面的一些实践做调整&#xff0c;通过实验 kubeadm 可以学习到 k8s 官方…

汇编试验五:编写、调试具有多个段的程序

ds 数据段放入数据正确&#xff1b; 两次push 操作后&#xff0c;ss栈段正确&#xff1b; 由于pop 操作顺序&#xff0c;ds数据段并没有发生改变&#xff1b; Source Code: assume cs:code, ds:data, ss:stackdata segmentdw 0123H,0456H,0789H,0abcH,0defH,0fedH,0cbaH,0987H …

SVN四部曲之SVN设置详解深入

想知道不同的设置是干什么用的&#xff0c;你只需将鼠标指针在编辑框/选项框上停留一秒钟...一个帮助提示气泡就会弹出来。 常规设置 图 4.68. 设置对话框&#xff0c;常规设置页面 这个对话框允许你指定自己喜欢的语言&#xff0c;同时也可做那些与Subversion相关的特殊设置。…

Vue3.2单文件组件setup的语法糖总结

目录 前言 setup语法糖 一、基本用法 二、data和methods 三、计算属性computed 四、监听器watch、watchEffect 五、自定义指令directive 六、import导入的内容可直接使用 七、声明props和emits 八、父组件获取子组件的数据 九、provide和inject传值 十、路由useRou…

自动判断PC端、手机端跳往不同的域名JS实现代码

输入相同域名&#xff0c;在pc端和移动端会出现不同的页面效果&#xff0c;一种是用栅格系统实现自适应&#xff0c; 更多的是设计两套不同的模板和两个二级域名或者一个主域名和一个二级域名&#xff08;就是有区别就可以了&#xff09;; js代码判断浏览器的用户代理头类别从而…

使用dotnet-monitor分析在Kubernetes的应用程序:Sidecar模式

dotnet-monitor可以在Kubernetes中作为Sidecar运行&#xff0c;Sidecar是一个容器&#xff0c;它与应用程序在同一个Pod中运行&#xff0c;利用Sidecar模式使我们可以诊断及监控应用程序。如下图所示&#xff0c;这是我们最终要实现的目标&#xff0c;通过可视化界面查看应用程…

C/C++语言的特点

一、支持数据封装和数据隐藏  在C中&#xff0c;类是支持数据封装的工具&#xff0c;对象则是数据封装的实现。C通过建立用户定义类支持数据封装和数据隐藏。  在面向对象的程序设计中&#xff0c;将数据和对该数据进行合法操作的函数封装在一起作为一个类的定义。对象被说…

JS中的扩展运算符(...)和剩余运算符(...)

文章目录 一、概念二、扩展运算符三、剩余运算符四、总结五、参考资料一、概念 在JS中&#xff0c;扩展运算符&#xff08;spread&#xff09;是三个点 (...) &#xff0c;剩余运算符&#xff08;rest&#xff09;也是三个点 (...) 二、扩展运算符 &#xff08;1&#xff09;基…

SFB 项目经验-07-Skype for Business 话机 Polycom CX700

本系列博文&#xff1a;Lync 项目经验-01-共存迁移-Lync2013-TO-SFB 2015-规划01http://dynamic.blog.51cto.com/711418/1858520 Lync 项目经验-02-共存迁移-Lync2013-TO-SFB 2015-规划02http://dynamic.blog.51cto.com/711418/1859143 Lync 项目经验-03-共存迁移-Lync2013-TO…

亿方云CEO程远:转型第一式:链接企业人与数据

传统企业一直在探讨如何做好互联网转型&#xff0c;那么互联网核心是什么&#xff1f;转型目标是什么&#xff1f;亿方云CEO程远在此次峰会上发表了自己看法&#xff0c;他认为快、人、连接是互联网核心基因&#xff0c;转型第一步就在于企业、人与数据的充分链接。中国企业的互…

Linux下Gcc 的编译过程

在linux下开发难免会用到gcc编译。GCC&#xff08;GNU Compiler Collection。GNU编译器套装&#xff09;&#xff0c;是由 GNU 开发的编程语言编译器。它是GNU编译器套装以GPL许可证所发行的自由软件&#xff0c;也是 GNU计划的关键部分。使用GCC编译程序时,编译过程能够被细分…

使用.NET简单实现一个Redis的高性能克隆版(七-完结)

译者注该原文是Ayende Rahien大佬业余自己在使用C# 和 .NET构建一个简单、高性能兼容Redis协议的数据库的经历。首先这个"Redis"是非常简单的实现&#xff0c;但是他在优化这个简单"Redis"路程很有趣&#xff0c;也能给我们在从事性能优化工作时带来一些启…

解决 Vue 里 Script 标签首层不缩进 - VS Code

问题&#xff1a; 在 vscode 使用 vue 的时候&#xff0c;发现 script 标签首层不缩进&#xff1f;&#xff1f;&#xff1f; 下载扩展&#xff1a;prettier 解决方法一&#xff1a; 打开 setting.json文件 添加&#xff1a;"prettier.vueIndentScriptAndStyle": tru…

Android应用开发性能优化完全分析

1 背景 其实有点不想写这篇文章的&#xff0c;但是又想写&#xff0c;有些矛盾。不想写的原因是随便上网一搜一堆关于性能的建议&#xff0c;感觉大家你一总结、我一总结的都说到了很多优化注意事项&#xff0c;但是看过这些文章后大多数存在一个问题就是只给出啥啥啥不能用&am…

ZBLOG-ASP2.2如何给图片增加ALT标签说明文字?

2019独角兽企业重金招聘Python工程师标准>>> 一直以来&#xff0c;我们在建设网站的时候&#xff0c;都容易犯下一个大错误&#xff0c;那就是没有重视图片的文字说明&#xff0c;而大多数时候&#xff0c;技术方面并不能很好的识别图片的内容&#xff0c;这也是受限…