加载中......
输入验证码,即可复制
微信扫码下载好向圈APP, 登陆后即可进入消息页面查看验证码
只需要3秒时间
    线程池优点:

1)降低线程创建和销毁线程造成的开销;

2)提高响应速度;任务到达时,相对于手工创建一个线程,直接从线程池中拿线程,速度肯定快很多;

3)提高线程可管理性;线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统稳定性,使用线程池可以进行统一分配、调优和监控;
    创建线程池
public ThreadPoolExecutor(int corePoolSize,                              int maximumPoolSize,                              long keepAliveTime,                              TimeUnit unit,                              BlockingQueue<Runnable> workQueue) {        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,             Executors.defaultThreadFactory(), defaultHandler);   }
1)corePoolSize:核心线程最大数量,线程池中常驻线程的最大数量;

2)maximumPoolSize:线程池中运行最大线程数(包括核心线程和非核心线程)

3)keepAliveTime:线程池中空闲线程(仅适用于非核心线程)所能存活的最长时间

4)unit:存活时间单位,与keepAliveTime搭配使用

5)workQueue:存放任务的阻塞队列

6)handler:线程池饱和策略
    线程池执行流程

1)从流程角度

Java多线程--线程池-1.jpg

2)从结构角度

Java多线程--线程池-2.jpg

3)处理流程
    判断线程池中核心线程数是否已达阈值corePoolSize,若否,则创建一个新核心线程执行任务若核心线程数已达阈值corePoolSize,判断阻塞队列workQueue是否已满,若未满,则将新任务添加进阻塞队列若满,再判断,线程池中线程数是否达到阈值maximumPoolSize,若否,则新建一个非核心线程执行任务。若达到阈值,则执行线程池饱和策略。

4)几种典型的工作队列
    ArrayBlockingQueue:使用数组实现的有界阻塞队列,特性先进先出LinkedBlockingQueue:使用链表实现的阻塞队列,特性先进先出,可以设置其容量,默认为Interger.MAX_VALUE,特性先进先出;PriorityBlockingQueue:使用平衡二叉树,实现的具有优先级的无界阻塞队列;DelayQueue:无界阻塞延迟队列,队列中每个元素均有过期时间,当从队列获取元素时,只有过期元素才会出队列,队列头元素是最快要过期的元素;SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作,必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态;

5)几种饱和策略
    AbortPolicy:直接抛出一个异常,默认策略;DiscardPolicy:直接丢弃任务;DiscardOldestPolicy:抛弃下一个将要被执行的任务(最旧任务);CallerRunsPolicy:主线程中执行任务;
    几种典型的线程池

SingleThreadExecutor

1)概念
    创建单个线程,它适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景;

2)实现
public static ExecutorService newSingleThreadExecutor() {    return new FinalizableDelegatedExecutorService       (new ThreadPoolExecutor(1, 1,                                0L, TimeUnit.MILLISECONDS,                                new LinkedBlockingQueue<Runnable>()));}
Java多线程--线程池-3.jpg

    当线程池中没有线程时,会创建一个新线程来执行任务。当前线程池中有一个线程后,将新任务加入LinkedBlockingQueue线程执行完第一个任务后,会在一个无限循环中反复从LinkedBlockingQueue 获取任务来执行。

3)特点
    核心线程数为1;最大线程数也为1;阻塞队列是LinkedBlockingQueue;keepAliveTime为0;

4)使用场景
    适用于串行执行任务场景

FixedThreadPool(固定数量线程池)

1)概念
    创建线程数量固定的线程池,当线程处于空闲状态时,他们并不会被回收,除非线程池被关闭;当所有的线程都处于活动状态时,新的任务都会处于等待状态,直到有线程空闲出来;

2)实现
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {    return new ThreadPoolExecutor(nThreads, nThreads,                                  0L, TimeUnit.MILLISECONDS,                                  new LinkedBlockingQueue<Runnable>(),                                  threadFactory);}
Java多线程--线程池-4.jpg

    如果当前运行的线程数少于corePoolSize,则创建新线程来执行任务;在线程数目达到corePoolSize后,将新任务放到LinkedBlockingQueue阻塞队列中;线程执行完(1)中任务后,会在循环中反复从LinkedBlockingQueue获取任务来执行;

3)特点
    核心线程数和最大线程数大小一样;没有所谓的非空闲时间,即keepAliveTime为0;阻塞队列为无界队列LinkedBlockingQueue;

4)使用场景
    适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务;

CacheThreadPool

1)概念
    创建缓冲线程池

2)实现
public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue<Runnable>());}
Java多线程--线程池-5.jpg

    先执行SynchronousQueue的offer方法提交任务,并查询线程池中是否有空闲线程来执行SynchronousQueue的poll方法来移除任务;如果有,则配对成功,将任务交给这个空闲线程,否则,配对失败,创建新的线程去处理任务;当线程池中的线程空闲时,会执行SynchronousQueue的poll方法等待执行SynchronousQueue中新提交的任务。若等待超过60s,空闲线程就会终止;

3)特点
    核心线程数为0;最大线程数为Integer.MAX_VALUE;即可以创建无限的非核心线程;阻塞队列是SynchronousQueue;非核心线程空闲存活时间为60秒;

4)使用场景
    执行大量短生命周期任务;因为maximumPoolSize是无界的,所以提交任务的速度 > 线程池中线程处理任务的速度就要不断创建新线程;每次提交任务,都会立即有线程去处理,因此CachedThreadPool适用于处理大量、耗时少的任务;

ScheduledThreadPoolExecutor

1)概念
    定时,周期性执行任务;

2)实现
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {        return new ScheduledThreadPoolExecutor(corePoolSize);}public ScheduledThreadPoolExecutor(int corePoolSize) {    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,          new DelayedWorkQueue());}
    工作流程:

    添加一个任务;线程池中的线程从 DelayQueue 中取任务;线程从 DelayQueue 中获取 time 大于等于当前时间的task;执行完后修改这个 task 的 time 为下次被执行的时间;这个 task 放回DelayQueue队列中;

    提交任务方式:schedule:自定义周期
//command:执行的任务Callable或Runnable接口实现类//delay:延时执行任务的时间//unit:延迟时间单位public ScheduledFuture<?> schedule(Runnable command,                       long delay, TimeUnit unit);
    scheduleAtFixedRate: 按照固定速率周期执行;
//command:执行的任务 Callable或Runnable接口实现类//initialDelay:第一次执行任务延迟时间//period:连续执行任务之间的周期,从上一个任务开始执行时计算延迟多少开始执行下一个任务,但是还会等上一个任务结束之后。//unit:initialDelay和period时间单位public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,                          long initialDelay,                          long period,                          TimeUnit unit);
    scheduleWithFixedDelay:上个任务延迟固定时间后执行;
//command:执行的任务 Callable或Runnable接口实现类//initialDelay:第一次执行任务延迟时间//period:连续执行任务之间的周期,从上一个任务全部执行完成时计算延迟多少开始执行下一个任务//unit:initialDelay和period时间单位public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,                             long initialDelay,                             long delay,                             TimeUnit unit);
3)特点
    最大线程数为Integer.MAX_VALUE;阻塞队列是DelayedWorkQueue;keepAliveTime为0;scheduleAtFixedRate() :按某种速率周期执行;scheduleWithFixedDelay():在某个延迟后执行;

4)使用场景
    周期性执行任务,并且需要限制线程数量的场景;
程序员圈
16937 查看 1 0 反对

说说我的看法高级模式

您需要登录后才可以回帖 登录|立即注册

  • 王者山王

    2021-2-24 08:41:48 使用道具

    来自: 北京来自: 北京来自: 北京来自: 北京
    转发了