Java并发系列:线程池与阻塞队列

本文主要介绍

  • Java线程池(ThreadPool)
    • FixedThreadPool
    • CachedThreadPool
    • ScheduleThreadPool
    • SingleThreadExecutor
    • SingleThreadScheduledExecutor
    • ForkJoinPool
  • 拒绝策略
    • AbortPolicy
    • DiscardPolicy
    • DiscardOldestPolicy
    • CallerRunsPolicy
  • 阻塞队列(WorkQueue)
    • LinkedBlockingQueue
    • ArrayBlockingQueue
    • SynchronousQueue
    • ConcurrentLinkedQueue
  • 自定义线程池
  • 本文涉及的源码

正文开始

Java线程池的原理

  • 线程池的设计原理类似于叫餐排队,首先餐厅有10个座位(CorePoolSize),来的人直接坐,后续来的人进行排队(WorkQueue),人来的再多的时候,餐厅立马增派人手,扩大到20个座位(MaxPoolsize),如果继续来人,那么剩下的人会被执行拒绝策略。
  • 线程池参数主要包括:CorePoolSize、WorkQueue、MaxPoolsize
  • 三者关系:当任务来的时候,首先核心线程数递增,然后后备的任务队列(阻塞队列)来装载,最后新增线程数至最大线程数,再多的话,就执行拒绝策略,结束的时候,大于corePoolSize的线程会根据KeepAliveTime参数来被回收。
  • KeepAliveTime:配合时间单位来使用,线程池会将超过KeepAliveTime,且无事可做的线程回收。
  • 线程工厂:用于创建线程,设置优先级,置于同一个线程组等。

Java线程池(ThreadPool)

  • FixedThreadPool
    • 固定线程数的线程池,即CorePoolSize == MaxPoolsize,
    • 拒绝策略是AbortPolicy
  • CachedThreadPool
    • 核心线程数为0,最大线程数为Integer.MAX_VALUE。
  • ScheduleThreadPool:主要包括三种方法
    • schedule:定时执行
    • scheduleAtFixedRate:定时执行后,按照固定的时间间隔进行再次执行
      • 【注意】:
        • 1、在main中不可以写service.shutdown(),否则执行不了,被关闭了
        • 2、如果任务执行时间大于间隔时间,那么按照执行时间来,比如执行需要10S,间隔定时5S,间隔时间到,任务还没有执行完,那么继续等待到任务结束后,再次执行该任务。相当于单线程循环在执行。
    • scheduleWithFixedDelay:定时执行,在执行结束后,间隔固定时间再次执行,具体见源码:ScheduleThreadPool_Demo。
  • SingleThreadExecutor
    • 仅有一个线程来执行任务,因此不会有线程安全问题
    • 如果线程在执行任务的时候,出现异常,会新建线程来继续执行。
public class SingleThreadExecutor_Demo {
     
    private static int count = 0;
    private static Runnable forsing = () -> {
     
        count++;
        //出现报错,但是继续执行
        if (count == 5) int y = count / 0;
        System.out.println("main中线程的名字:" + Thread.currentThread().getName() + "count:" + count);
    };
    
    public static void main(String[] args) {
     
        ExecutorService service = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 500; i++) service.execute(forsing);
        service.shutdown();
    }
}
  • SingleThreadScheduledExecutor

  • ForkJoinPool

拒绝策略

  • AbortPolicy
    • 对外抛出异常,由业务决定如何处理。
  • DiscardPolicy
    • 新任务来的时候悄无声息的直接丢弃,会造成数据丢失。
  • DiscardOldestPolicy
    • 悄无声息的直接丢弃最老的一个任务,会造成数据丢失。
  • CallerRunsPolicy
    • 交给提交任务的线程执行。

阻塞队列(WorkQueue)

  • LinkedBlockingQueue
    • 无界阻塞队列
  • ArrayBlockingQueue
    • 有界阻塞队列
  • SynchronousQueue
    • 同步队列,立即交付,队列长度为0
  • ConcurrentLinkedQueue
    • 其实是非阻塞队列
    • 无界队列

自定义线程池

  • 选择合适的线程池进行自定义
public static ExecutorService get(int corePoolSize){
     
    return new ThreadPoolExecutor(
            corePoolSize, 
            20,
            60L, 
            TimeUnit.SECONDS,
            new LinkedBlockingDeque<>());
}

参考博客:java常用的几种线程池比较

你可能感兴趣的:(高并发,高可用,高性能专题,java,并发编程,多线程,线程池)