Java 常用线程池

Java 常用线程池

1.Executor、ExecutorService、ScheduledExecutorService、ScheduledThreadPoolExecutor、ThreadPoolExecutor、Executors的关系

关系说明:

​ 1. Executor是顶级接口,但是它只是执行线程的工具而不是线程池,定义了一个无返回值的execute方法;

​ 2. ExecutorService接口继承了Executor,是真正的线程池接口

​ 3. ScheduledExecutorService继承了ExecutorService,ScheduledThreadPoolExecutor继承了

​ ThreadPoolExecutor,实现了ScheduledExecutorService

​ 4.ThreadPoolExecutor实现了ExecutorService

​ 5.Executors类里面提供了一些静态工厂,生成一些常用的线程池。

2.常用线程池
  • ThreadPoolExecutor的构造方法
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 
    

    各个参数的含义:

    corePoolSize:核心线程数

    maximumPoolSize:最大线程数

    keepAliveTime:当线程池中存活的线程数超过了核心线程数,且这些多余的线程为空闲线程,这个参数代表这些空间线程的最长存活时间,超过这个时间就会被销毁

    unit:存活时间的单位

    workQueue:任务队列,将用户提交的任务加入到任务队列中

    对工作队列的说明:

    ​ 工作队列是代表提交待执行任务的队列。它是BolckingQueue接口的对象,仅用于存储Runnable任务。根据任务功能不同,可以在ThreadPoolExecutor构造方法中使用如下几种阻塞队列:

    • 直接提交队列:由synchronousQueue对象提供,该队列没有容量,提交给线程池的任务不会被真实保存,总是将新任务交给线程执行,如果没有空余线程,就尝试创建新的线程,如果线程达到maximumPoolSize 指定的最大线程,就执行拒绝策略。

    • 有界队列:由ArrayBlockingQueue实现(先入先出),在创建ArrayBlockingQueue对象时,可以指定一个容量。当有任务需要执行时,且现在线程池中的线程数小于核心线程数就创建线程,如果超过了核心线程数则放入等待队列;如果队列已满,则在线程池中线程数小于maximumPoolSize 的情况下创建新的线程;如果超过了maximumPoolSize 的大小,则执行拒绝策略。

    • 无界队列:由LinkedBlockingQueue对象实现(先入先出),与有界队列相比,除非系统资源耗尽,否则不会存在任务入队失败的情况;当有新任务时,在系统线程小于corePoolSize时创建线程;当大于corePoolSize则把任务加入阻塞队列(因为不存在阻塞队列会满的情况,因此不用像有界队列一样,当阻塞队列满了以后继续创建线程)

    • 优先任务队列:通过PriorityBlockingQueue实现,通过任务优先级先后顺序执行。

    threadFactory:线程工厂,用于创建线程

    handle:拒绝策略,当任务太多,线程池不能处理时,怎么应对这样的情况

    ThreadPoolExecutor构造方法的最后一个参数表示拒绝策略。当提交给线程迟的任务量超过了实际承载能力时如何处理?也就是说线程池的线程已经用完了,等待队列也满了,无法为新的任务提供服务,那么就采用拒绝策略来解决这个问题,JDK提供了四种拒绝策略:

    • AbortPolicy:抛出异常(JDK中默认选择的方式)
    • CallerRunsPolicy:只要线程池没关闭,会在调用者线程运行当前负载的任务
    • DiscardOldestPolicy:只要线程池没关闭,将队列中最老的任务丢弃,并再次尝试提交新任务
    • DiscardPolicy:直接丢弃

    Executors中定义的三个线程池:

  • newSingleThreadPool():单线程复用的线程池
    public static ExecutorService newSingleThreadExecutor() {
            return new FinalizableDelegatedExecutorService
                //通过ThreadPoolExecutor产生的线程池,核心线程数和最大线程数都是1
                //无界队列
                (new ThreadPoolExecutor(1, 1,
                                        0L, TimeUnit.MILLISECONDS,
                                        new LinkedBlockingQueue<Runnable>()));
        }
    

    特点:使用单个工作线程执行任务

  • newFixedThreadPool():固定大小的线程池

  •  public static ExecutorService newFixedThreadPool(int nThreads) {
         	//核心线程数和最大线程数都是n
         	//采用无界队列
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
        }
    

    特点:特点就是可以重用固定数量线程的线程池

  • newCachedThreadPool():创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,

    那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

  •     public static ExecutorService newCachedThreadPool() {
            //核心线程数为0,最大线程数为Integer.MAX_VALUE
            //采用直接提交队列
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>());
        }
    

    特点:

    1. 如果线程池中的线程数超过实际任务需要,在60s的时间后这些空闲线程会被回收;若当前线程数低于实际任务需要,则会不断创建线程

    2. SynchronousQueue队列是一个直接提交队列,它是一个没有容量的阻塞队列。每个插入操作必须等待另一个线程的对应移除操作。这意味着,如果主线程提交任务的速度高于线程池中处理任务的速度时,CachedThreadPool会不断创建新线程。极端情况下,CachedThreadPool会因为创建过多线程而耗尽CPU资源。

    执行过程如下:

    1.首先执行SynchronousQueue.offer(Runnable task)。如果在当前的线程池中有空闲的线程正在执行SynchronousQueue.poll(),那么主线程执行的offer操作与空闲线程执行的poll操作配对成功,主线程把任务交给空闲线程执行。,execute()方法执行成功,否则执行步骤2

    2.当线程池为空(初始maximumPool为空)或没有空闲线程时,配对失败,将没有线程执行SynchronousQueue.poll操作。这种情况下,线程池会创建一个新的线程执行任务。

    3.在创建完新的线程以后,将会执行poll操作。当步骤2的线程执行完成后,将等待60秒,如果此时主线程提交了一个新任务,那么这个空闲线程将执行新任务,否则被回收。因此长时间不提交任务的CachedThreadPool不会占用系统资源。

    说明:SynchronousQueue是一个不存储元素阻塞队列,每次要进行offer操作时必须等待poll操作,否则不能继续添加元素。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值