Java线程池

一、核心组件

  • 线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;

  • 工作线程(WorkThread):线程池中执行任务的具体线程,在没有任务时处于等待状态,可以循环的执行任务;

  • 任务接口(Task):用于定义工作线程的调度和执行策略,只有线程实现了该接口,线程中的任务才能够被线程池调度;

  • 任务队列(taskQueue):存放待处理的任务。提供一种缓冲机制。

二、线程池架构

在这里插入图片描述
ThreadPoolExecutor是构建线程的核心实现类,ThreadPoolExecutor继承自AbstractExecutorService,而AbstractExecutorService实现了ExecutorService接口。

ThreadPoolExecutor构造函数:

在这里插入图片描述

  • corePoolSize :线程池中核心线程数的最大值
  • maximumPoolSize :线程池中能拥有最多线程数
  • keepAliveTime :表示空闲线程的存活时间
  • TimeUnit unit :表示keepAliveTime的单位
  • workQueue:用于缓存任务的阻塞队列
  • threadFactory :指定创建线程的工厂(可以不指定)
  • handler :表示当 workQueue 已满,且池中的线程数达到 maximumPoolSize 时,线程池拒绝添加新任务时采取的策略(可以不指定)

三、线程池工作流程

  1. 如果有空闲线程,则直接执行该任务;
  2. 如果没有空闲线程,且当前运行的线程数 < corePoolSize,则创建新的线程执行该任务;
  3. 如果没有空闲线程,且当前的线程数 ≥ corePoolSize,同时阻塞队列未满,则将任务入队列,而不添加新的线程;
  4. 如果没有空闲线程,且阻塞队列已满,同时池中的线程数 < maximumPoolSize ,则创建非核心线程执行任务;
  5. 如果没有空闲线程,且阻塞队列已满,同时池中的线程数 ≥ maximumPoolSize ,则根据构造函数中的 handler 指定的策略来拒绝新的任务。
  6. 线程空闲时间超过keepAliveTime 时,正在运行的线程数量超过corePoolSize,该线程会被认定为空闲线程并停止。因此在线程池中所有线程任务都执行完毕后,线程会收缩到corePoolSize大小。

在这里插入图片描述

四、线程池拒绝策略

当提交的任务数大于(workQueue.size() + maximumPoolSize ),就会触发线程池的拒绝策略。

JDK内置四种拒绝策略,默认的拒绝策略在ThreadPoolExecutor中作为内部类提供。在默认的拒绝策略不能满足应用需求时,可以自定义拒绝策略。

  • AbortPolicy :直接抛出异常,阻止线程正常运行。
  • CallerRunsPolicy :如果被丢弃的线程任务未关闭,则执行该线程任务。
  • DiscardOldestPolicy :移除阻塞队列 workQueue 中最老的一个任务,并将新任务加入。
  • DiscardPolicy - 直接丢弃当前线程任务而不做任何处理。

四种拒绝策略是相互独立无关的,选择何种策略去执行,还得结合具体的业务场景。实际工作中,一般直接使用 ExecutorService 的时候,都是使用的默认的 defaultHandler ,也即 AbortPolicy 策略

五、常用线程池

在这里插入图片描述

(1)newCachedThreadPool(可缓存的线程池)

  • newCachedThreadPool用于创建一个可缓存线程池,之所以叫可缓存线程池,是因为它在创建新线程时如果有可重用的线程,则重用它们,否则创建一个新线程并将其添加到线程池中;
  • 在线程池的keepAliveTime时间超过默认的60秒后,该线程会被终止并从缓存中移除,因此在没有线程任务运行时,newCachedThreadPool将不会占用系统的线程资源;
  • 在有执行时间很短的大量任务需要执行的情况下,newCachedThreadPool能很好地复用运行中的线程资源来提高系统的运行效率
ExecutorService pool = Executors.newCachedThreadPool();

(2)newFixedThreadPool(固定大小的线程池)

  • newFixedThreadPool用于创建一个固定线程数量的线程池
  • 如果任务数量大于等于线程池中线程的数量,则新提交的任务将在阻塞队列中排队,直到有可用的线程资源;
ExecutorService pool = Executors.newFixedThreadPool(10);

(3)newScheduledThreadPool(可做任务调度的线程池)

newScheduledThreadPool用于创建可定时调度的线程池,可设置在给定延迟时间后执行或定期执行某个线程任务。

public class Test{
    public static void main(String[] args) {
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);

        // 创建一个延迟3秒执行的线程
        pool.schedule(new Runnable() {
            public void run() {
                System.out.println("delay 3 seconds" + Thread.currentThread().getName());
            }
        }, 3, TimeUnit.SECONDS);
        // 创建一个延迟3秒且每1秒执行一次的线程
        pool.scheduleAtFixedRate(new Runnable() {
            public void run() {
                System.out.println("delay 3 second and repeat execute every 1 seconds" + Thread.currentThread().getName());
            }
        }, 3, 1, TimeUnit.SECONDS);

        // 关闭线程池
//        pool.shutdown();
    }
}

delay 3 secondspool-1-thread-1
delay 3 second and repeat execute every 1 secondspool-1-thread-2
delay 3 second and repeat execute every 1 secondspool-1-thread-2
delay 3 second and repeat execute every 1 secondspool-1-thread-2

(4)newSingleThreadPool(单个线程的线程池)

  • newSingleThreadPool创建的线程池会确保池中永远有且只有一个可用的线程
  • 在该线程停止或发生异常时,newSingleThreadPool线程池会启动一个新的线程代替该线程继续执行任务;
ExecutorService pool = Executors.newSingleThreadExecutor();

(5)newWorkStealingPool(足够大小的线程池)

  • newWorkStealingPool用于创建持有足够线程的线程池来达到快速运算的目的;
  • 在内部通过使用多个队列来减少各个线程调度产生的竞争;
  • 足够的线程指JDK根据当前线程的运行需求向操作系统申请足够的线程,以保障线程的快速执行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值