线程池详解

原文:https://blog.csdn.net/Lj_18210158431/article/details/81990535

jdk1.5引入Executor线程池框架,通过它把任务的提交和执行进行解耦,只需要定义好任务,然后提交给线程池,而不用关心该任务是如何执行、被哪个线程执行,以及什么时候执行。

1.初始化线程池(4种)

简介:

Java线程池的工厂类:Executors类,

初始化4种类型的线程池:

1.newFixedThreadPool()
说明:初始化一个指定线程数的线程池,其中corePoolSize == maxiPoolSize,使用LinkedBlockingQuene作为阻塞队列
特点:即使当线程池没有可执行任务时,也不会释放线程。

使用场景:用于负载比较重的服务器,为了资源的合理利用,需要限制当前线程数量。


2.newCachedThreadPool()
说明:初始化一个可以缓存线程的线程池,默认缓存60s,线程池的线程数可达到Integer.MAX_VALUE,即2147483647,内部使用SynchronousQueue作为阻塞队列;
特点:在没有任务执行时,当线程的空闲时间超过keepAliveTime,会自动释放线程资源;当提交新任务时,如果没有空闲线程,则创建新线程执行任务,会导致一定的系统开销;
因此,使用时要注意控制并发的任务数,防止因创建大量的线程导致而降低性能。

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


3.newSingleThreadExecutor()
说明:初始化只有一个线程的线程池,内部使用LinkedBlockingQueue作为阻塞队列。
特点:如果该线程异常结束,会重新创建一个新的线程继续执行任务,唯一的线程可以保证所提交任务的顺序执行。

使用场景:用于串行执行任务的场景,每个任务必须按顺序执行,不需要并发执行。


4.newScheduledThreadPool()
特定:初始化的线程池可以在指定的时间内周期性的执行所提交的任务,在实际的业务场景中可以使用该线程池定期的同步数据。

总结:除了newScheduledThreadPool的内部实现特殊一点之外,其它线程池内部都是基于ThreadPoolExecutor类(Executor的子类)实现的。

 

2.ThreadPoolExecutor内部具体实现:

(1)ThreadPoolExecutor类构造器语法形式:

ThreadPoolExecutor(corePoolSize,maxPoolSize,keepAliveTime,timeUnit,workQueue,threadFactory,handle);   方法参数:
  corePoolSize:核心线程数
  maxPoolSize:最大线程数
     keepAliveTime:线程存活时间(在corePore<*<maxPoolSize情况下有用)
     timeUnit:存活时间的时间单位
     workQueue:阻塞队列(用来保存等待被执行的任务)
     threadFactory:线程工厂,主要用来创建线程;
     handler:表示当拒绝处理任务时的策略,有以下四种取值(饱和策略)

 

(2)注:关于workQueue参数的取值,JDK提供了4种阻塞队列

列类型供选择:
   ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;
   InkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任务,吞吐量通常要高于  
     SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直             于阻塞状态,吞吐量通常要高于ArrayBlockingQuene;
   PriorityBlockingQuene:具有优先级的无界阻塞队列;     
    

   (3)handler:表示当拒绝处理任务时的策略,有以下四种取值(饱和策略)

       问:最大线程数如果满了该如何处理?可使用饱和策略解决。

            工作队列就有两种实现策略:无界队列和有界队列。无界队列不存在饱和的问题,但是其问题是当请求持续高负载的话,任务会无脑的加入工作队列,那么很可能导致内存等资源溢出或者耗尽。而有界队列不会带来高负载导致的内存耗尽的问题,但是有引发工作队列已满情况下,新提交的任务如何管理的难题,这就是线程池工作队列饱和策略要解决的问题。

饱和策略分为:Abort 策略, CallerRuns 策略,Discard策略,DiscardOlds策略。

 注: 当线程池的饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池提供了4种策略: 

          ThreadPoolExecutor.AbortPolicy:默认策略,新任务提交时直接抛出未检查的异常RejectedExecutionException异常。该异常可由调用者捕获。

            ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

    ThreadPoolExecutor.DiscardPolicy:新提交的任务被抛弃,但是不抛出异常。

    ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(不适合工作队列为优先队列场景)

    当然也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。

3.应用场景:

多线程最多的场景:;

多线程的常见应用场景:

1.web服务器本身;各种专用服务器(如游戏服务器)

2、后台任务,例如:定时向大量(100w以上)的用户发送邮件;

3、异步处理,例如:发微博、记录日志等;

4、分布式计算

4.总结:

线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于corePoolSize;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;如果阻塞队列满了,那就创建新的线程执行当前任务;直到线程池中的线程数达到maxPoolSize,这时再有任务来,只能执行reject()处理该任务;

注:如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有核心线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值