线程池原理 详细

为什么要使用线程池?

当某个线程类的所需运行时间短且需频繁启动时,应用程序需要频繁的创建线程、销毁线程、线程切换。单个线程的创建、销毁消耗的系统cpu、内存等资源很少,但庞大的数量将耗费很多的资源,且频繁的线程切换也将消耗许多的cpu资源。
使用线程池的好处

  • 某个线程执行完任务后不会被销毁,而是等待执行下一个任务,这样线程得以复用,也就没有频繁创建、销毁线程的消耗。
  • 当任务到达时不用创建线程,由线程池中的线程执行,因此响应时间更短
  • 线程在线程池中便于管理、监控、调优

线程池原理

关键类ThreadPoolExecutor

uml图
在这里插入图片描述
Executor:接口,只定义了void execute(Runnable command)方法。
ExecutorService: 接口,继承了Executor,增加了shutdown、shutdownNow、submit等方法。
AbstractExecutorService:抽象类,实现了ExecutorService的submit等方法。
ThreadPoolExecutor:继承了AbstractExecutorService,实现了execute、shutdown、shutdownNow等方法。
ScheduledThreadPoolExecutor:继承ThreadPoolExecutor、实现ScheduledExecutorService接口,在ThreadPoolExecutor的基础上实现了ScheduledExecutorService的schedule系列方法。

相关方法解释
execute:运行Runnable任务,无返回值。
submit:运行任务,底层调用execute,返回Future对象。
shutdown:线程池状态设置为SHUTDOWN,不再接受新的任务,完成正在执行的任务,完成缓存队列中的任务,之后线程池状态设置为TERMINATED。
shutdownNow:线程池状态设置为STOP,不再接受新的任务,终止正在执行的任务,丢弃缓存队列中的任务,之后线程池状态设置为TERMINATED。

ThreadPoolExecutor构造器

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

corePoolSize:核心线程池大小,创建的ThreadPoolExecutor默认未创建线程,调用prestartAllCoreThreads创建corePoolSize个线程。
maximumPoolSize: 线程池最大线程数,线程池线程数上限。
keepAliveTime:当线程数大于corePoolSize时,某个线程空闲时间达到keepAliveTime时将被销毁,直到线程数不大于corePoolSize。当corePoolSize等于maximumPoolSize时,keepAliveTime无作用。
unit:keepAliveTime的时间单位,有MILLISECONDS、SECONDS等。
workQueue:缓存队列,当线程数等于corePoolSize,且这些线程都有任务执行时,新的任务存入workQueue,等待执行。

常见BlockQueue
ArrayBlockingQueue: 有界阻塞队列,创建后不能改变容量
LinkedBlockingQueue: 可选有界阻塞队列,空参构造出的LinkedBlockingQueue大小为Integer.MAX_VALUE。
SynchronousQueue: 容量为零
threadFactory:创建线程的工厂。
handler:当线程数等于maximumPoolSize时,新的任务将被拒绝处理器handler处理。
拒绝处理器(拒绝策略)

  • AbortPolicy: 丢弃任务,抛出RejectedExecutionException。
  • DiscardPolicy: 仅丢弃任务
  • DiscardOldestPolicy: 丢弃缓程数冲队列中最老的任务,对新任务调用execute方法。
  • CallerRunsPolicy: 调用拒绝处理器的调用者所在的线程执行任务。
    这些拒绝处理器的源码都很简单。通过实现RejectedExecutionHandler接口,可以自定义拒绝处理器。

线程池提交任务的流程:
在这里插入图片描述

Executors的一些静态方法

newFixedThreadPool: 固定大小线程池,线程数固定为nThreads,缓冲队列大小为Integer.MAX_VALUE。

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

newSingleThreadExecutor: 单个线程,缓冲队列大小为Integer.MAX_VALUE。

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

newCachedThreadPool: 线程池提交新任务,若池中的线程均在执行任务,创建一个线程执行新任务。当某线程空闲时间达到60秒时,销毁该线程。可根据处理需要灵活调整线程数。

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    }

newScheduledThreadPool: 可定时执行任务,可周期执行任务。

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

ScheduledThreadPoolExecutor
继承ThreadPoolExecutor、实现ScheduledExecutorService接口,在ThreadPoolExecutor的基础上实现了ScheduledExecutorService的schedule系列方法。可定时执行任务,可周期执行任务。

ForkJoinPool
ForkJoinPool用于运行ForkJoinTask的ExecutorService。ForkJoinPool是一个用于并行处理任务的框架,不断把大的任务fork成小的任务直至可执行,之后并行执行,小的任务join把结果合并起来。ForkJoinPool的默认工作线程数是cpu的核数,每个工作线程都对应一个双端工作队列。ForkJoinPool的一个特点是采用了工作窃取(work-stealing),线程执行完自己的工作队列中的任务时,线程会随机从其他线程的工作队列的头部窃取任务来执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值