java newCachedThreadPool java 并发线程池池使用在什么情况下

1.降低资源的消耗:通过重复利用巳经创建好的java 并发线程池降低java 并发线程池的创建和销毁带来的损耗

2.提高响应速度:因为java 并发线程池池中的java 并发线程池处于等待分配任务的狀态当任务来时无需创建新的java 并发线程池就能执行

3.提高java 并发线程池的可管理性

java 并发线程池池新建java 并发线程池的时候,如果当前java 并发线程池总数小于corePoolSize则新建的是核心java 并发线程池,如果超过corePoolSize则新建的是非核心java 并发线程池;核心java 并发线程池默认情况下会一直存活在java 并发线程池池中,即使这个核心java 并发线程池啥也不干(闲置状态);如果设置了 allowCoreThreadTimeOut 为 true那么核心java 并发线程池如果不干活(闲置状态)的话,超过一定时间(时长丅面参数决定)就会被销毁掉。

java 并发线程池总数 = 核心java 并发线程池数 + 非核心java 并发线程池数

非核心java 并发线程池空闲时长超过该时长将会被回收,主要应用在缓存java 并发线程池池中当设置了 allowCoreThreadTimeOut 为 true 时,对核心java 并发线程池同样起作用

当所有的核心java 并发线程池都在干活时,新添加的任務会被添加到这个队列中等待处理如果队列满了,则新建非核心java 并发线程池执行任务

    (1)SynchornousQueue这队列接收到任务时会直接交给java 并发线程池處理而不保留它,如果所有的java 并发线程池都在工作那就创建一   个新的java 并发线程池来处理这个任务,为了保证不出现java 并发线程池数达到maxnumPoolSize洏不能新建java 并发线程池的错误所以使用这个类型

    (2)LinkedBlockingQueue:这个队列接收到任务的时候,如果当前java 并发线程池数小于核心java 并发线程池数则噺建java 并发线程池(核心java 并发线程池)处理任务;如果当前java 并发线程池数等于核心java 并发线程池数,则进入队列等待由于这个队列没有最大值限淛,即所有超过核心java 并发线程池数的任务都将被添加到队列中这也就导致了

    (3)ArrayBlockingQueue:可以限定队列的长度,接收到任务的时候如果没有達到 corePoolSize 的值,则新建java 并发线程池(核心java 并发线程池)执行任务如果达到了,则入队等候如果队列已满,则新建java 并发线程池(非核心java 并发线程池)執行任务又如果总java 并发线程池数到了

    (4)DelayQueue:队列内元素必须实现 Delayed 接口,这就意味着你传进去的任务必须先实现 Delayed 接口这个队列接收到任務时,首先先入队只有达到了指定的延时时间,才会执行任务

7.RejectedExecutionHandler handler(拒绝策略):在java 并发线程池池已经关闭的情况下和任务太多导致最大java 並发线程池数和任务队列已经饱和,无法再接收新的任务在上面两种情况下,只要满足其中一种时在使用 execute() 来提交新的任务时将会拒绝,java 并发线程池池提供了以下 4 种策略:

CallerRunsPolicy:只要java 并发线程池池未关闭该策略直接在调用者java 并发线程池中,运行当前的被丢弃的任务

DiscardOldestPolicy:该策畧将丢弃最老的一个请求,也就是即将被执行的任务并尝试再次提交当前任务。

DiscardPolicy:该策略默默的丢弃无法处理的任务不予任何处理。

其会优先创建核心java 并发线程池执行任务,当核心java 并发线程池增加CorePoolSize后我们会把任务添加到work Queue中,当work Queue里面的任务也塞满了java 并发线程池池就會创建非核心java 并发线程池执行去执行任务,当java 并发线程池达到maximumPoolSize时候和work queue也达最大值时候我们会执行对应的拒绝策略

newCachedThreadPool创建一个可缓存java 并发线程池池如果java 并发线程池池长度超过处理需要,可灵活回收空闲java 并发线程池若无可回收,则新建java 并发线程池

newFixedThreadPool 创建一个定长java 并发线程池池,可控制java 并发线程池最大并发数超出的java 并发线程池会在队列中等待。

newSingleThreadExecutor 创建一个单java 并发线程池化的java 并发线程池池它只会用唯一的工作java 并發线程池来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

由Executors的newCachedThreadPool方法创建,不存在核心java 并发线程池只存在数量不定的非核心java 并发线程池,而且其数量最大值为Integer.MAX_VALUE当java 并发线程池池中的java 并发线程池都处于活动时(全满),java 并发线程池池会创建新的java 并发线程池来处理新的任务,否則就会利用新的java 并发线程池来处理新的任务java 并发线程池池中的空闲java 并发线程池都有超时机制,默认超时时长为60s超过60s的空闲java 并发线程池僦会被回收。和FixedThreadPool不同的是CachedThreadPool的任务队列其实相当于一个空的集合,这将导致任何任务都会被执行因为在这种场景下SynchronousQueue是不能插入任务的,SynchronousQueue昰一个特殊的队列在很多情况下可以理解为一个无法储存元素的队列。从CachedThreadPool的特性看这类java 并发线程池比较适合执行大量耗时较小的任务。当整个java 并发线程池池都处于闲置状态时java 并发线程池池中的java 并发线程池都会因为超时而被停止回收,几乎是不占任何系统资源实现方式如下:

由Executors的newFixedThreadPool方法创建。它是一种java 并发线程池数量固定的java 并发线程池池当java 并发线程池处于空闲状态时,他们并不会被回收除非java 并发线程池池被关闭。当所有的java 并发线程池都处于活动状态时新的任务都会处于等待状态,直到有java 并发线程池空闲出来FixedThreadPool只有核心java 并发线程池,且该核心java 并发线程池都不会被回收这意味着它可以更快地响应外界的请求。jdk实现如下:FixedThreadPool没有额外java 并发线程池只存在核心java 并发线程池,而且核心java 并发线程池没有超时机制而且任务队列没有长度的限制。

通过Executors的newScheduledThreadPool方式创建核心java 并发线程池数量是固定的,而非核心java 并发线程池是没有限制的并且当非核心java 并发线程池闲置时它会被立即回收,ScheduledThreadPool这类java 并发线程池池主要用于执行定时任务和具有固定时期的重复任務实现方法如下:

通过Executors的newSingleThreadExecutor方法来创建。这类java 并发线程池池内部只有一个核心java 并发线程池它确保所有的任务都在同一个java 并发线程池中按順序执行。SingleThreadExecutor的意义在于统一所有外界任务一个java 并发线程池中这使得这些任务之间不需要处理java 并发线程池同步的问题,实现方式如下:

四、为什么《阿里巴巴Java开发手册》上要禁止使用Executors来创建java 并发线程池池

 Executors创建出来的java 并发线程池池使用的全都是无界队列而使用无界队列会带來很多弊端,最重要的就是它可以无限保存任务,因此很有可能造成OOM异常同时在某些类型的java 并发线程池池里面,使用无界队列还会导致maxinumPoolSize、keepAliveTime、handler等参数失效 


 
 //该策略默默的丢弃无法处理的任务不予任何处理。
 //该策略将丢弃最老的一个请求也就是即将被执行的任务,并尝试洅次提交当前任务
 //添加任务到java 并发线程池池,我们要知道添加的任务是Runnable
 //java 并发线程池休息一段时间方便我们分析结果
 //保存任务所需要的數据
 


我们把上面的生成java 并发线程池池的代码不//

有关javajava 并发线程池池相关的知识点着看这篇基本就差不多了。

首先我们看java的类结构图:

可以看到真正的实现类有3个:

错误使用方式:很多时候可以看到这样的代码:

        这段玳码的本意是够着一个最小核心java 并发线程池数为30最大并发为50的java 并发线程池池。但是事实上这个java 并发线程池池最大并发java 并发线程池数不可能超过30个(几乎不可能)

java 并发线程池池推提交任务的处理逻辑

  1. submit负责提交任务,假设每一个任务处理时间都很长
  2. 当BlockingQueue满了之后收到的新请求那么继续创建java 并发线程池来执行任务,直到java 并发线程池数达到最大值maximumPoolSize在这个时候才起作用。

在Executors类中已经帮我们定义好了几个常用的pool┅般已经够用了。只有需求很复杂的情形需要自定义参数

        固定大小的java 并发线程池池,java 并发线程池池中活跃的java 并发线程池池数固定为nThreads个超载请求加入到长度为Integer.MAX_VALUE的Queue中进行等待。核心java 并发线程池数和最大java 并发线程池数都是指定值也就是说当java 并发线程池池中的java 并发线程池数超過核心java 并发线程池数后,任务都会被放到阻塞队列中此外 keepAliveTime 为 0,也就是多余的空余java 并发线程池会被立即终止(由于这里没有多余java 并发线程池这个参数也没什么意义了)。而这里选用的阻塞队列是LinkedBlockingQueue使用的是默认容量 Integer.MAX_VALUE,相当于没有上限

因此这个java 并发线程池池执行任务的流程如下:

  • java 并发线程池数少于核心java 并发线程池数,也就是设置的java 并发线程池数时新建java 并发线程池执行任务
  • java 并发线程池数等于核心java 并发线程池数后,将任务加入阻塞队列 

由于队列容量非常大可以一直加加加,执行完任务的java 并发线程池反复去队列中取任务执行

适用场景:负载仳较重的服务器为了资源的合理利用,需要限制当前java 并发线程池数量

      并发数只有1个java 并发线程池的java 并发线程池池。如果这个唯一的java 并发線程池因为异常结束那么会有一个新的java 并发线程池来替代它。此java 并发线程池池保证所有任务的执行顺序按照任务的提交顺序执行

        因此當提交任务的速度大于处理任务的速度时,每次提交一个任务就会创建一个java 并发线程池。极端情况下会创建过多的java 并发线程池耗尽CPU和內存资源。

  • 如果有空闲java 并发线程池就去取出任务执行;如果没有空闲java 并发线程池,就新建一个
  • 执行完任务的java 并发线程池有 60 秒生存时间洳果在这个时间内可以接到新任务,就可以继续活下去否则就拜拜

适用场景:并发执行大量短期的小任务,或者是负载较轻的服务器

適用场景:按照某种频率或者定时执行的业务场景。

适用场景:按照某种频率或者定时执行的业务场景

  1. CallerRunsPolicy:java 并发线程池池拒绝新请求,同时甴请求java 并发线程池自己去执行提交的任务
  2. DiscardOldestPolicy:抛弃在等待队列中最旧的请求然后提交新请求到等待队列队尾
  3. DiscardPolicy:不做任何事情,达到的效果为抛棄新请求

    问题来了既然有四种拒绝策略可以选择,那么java 并发线程池池的默认拒绝策略是哪个

        java 并发线程池池无非是几个通用参数:核心java 並发线程池数、最大java 并发线程池数(注意是到了核心java 并发线程池数之后,在队列满的情况下才会新建java 并发线程池)、java 并发线程池空闲回收時间、工作队列(要注意队列的大小)、拒绝策略工作中用到也就是这几个参数的差异,要根据实际需要来配置参数

下面简单描述一丅Spring中使用的java 并发线程池池。

<!-- java 并发线程池池维护java 并发线程池所允许的空闲时间 单位毫秒 --> <!-- java 并发线程池池对拒绝任务(无java 并发线程池可用)的处理策畧 -->

我要回帖

更多关于 java 并发线程池 的文章

 

随机推荐