深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?

文章目录

    • 1.为什么要使用线程池?降低了之前频繁创建与销毁线程所带来的资源损耗
    • 2.线程池是干嘛的?控制运行的线程的数量
    • 3.主要特点
      • ①线程复用:降低资源消耗
      • ②控制最大并发数:提高响应速度
      • ③管理线程:提高线程的可管理性
    • 4.线程池原理
      • 1)一问:线程池底层是什么?ThreadPoolExecutor
      • 2)二问:线程池创建线程的5种方法?1,2了解3,4,5重要
        • ①了解2
        • ②重要3
        • ③代码简单使用
      • 3)三问:讲了这么多线程池创建线程的方法,你会使用哪个?使用自定义的!
        • ①Demo自定义线程池
        • ②总结:线程池可处理的任务数=最大线程数+阻塞队列长度
    • 5.线程池七大参数
      • 1)线程池的拒绝策略
    • 6.线程池的工作流程
    • 7.如何合理的配置线程池参数,比如最大线程数?
      • ①查看当前电脑配置-->CPU核心数
      • ②根据具体业务情况分析,CPU密集或IO密集
        • 1)CPU密集,CPU核心数+1个线程的线程池
        • 2)IO密集,①CPU核心数*2;②CPU核心数/(1-阻塞系数),阻塞系数0.8~0.9


1.为什么要使用线程池?降低了之前频繁创建与销毁线程所带来的资源损耗

2.线程池是干嘛的?控制运行的线程的数量

主要控制运行的线程的数量,处理过程中将任务放入队列中,然后在线程创建后启动这些任务,如果线程的数量超过了最大数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。

3.主要特点

①线程复用:降低资源消耗

②控制最大并发数:提高响应速度

③管理线程:提高线程的可管理性

深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第1张图片

4.线程池原理

1)一问:线程池底层是什么?ThreadPoolExecutor

ThreadPoolExecutor类

ThreadPoolExecutor类

ThreadPoolExecutor类

ExecutorService,Executors

重要的事情说三遍!!!

深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第2张图片

  • corePoolSize : 表示线程池核心线程数,当初始化线程池时,会创建核心线程进入等待状态,即使它是空闲的,核心线程也不会被摧毁,从而降低了任务一来时要创建新线程的时间和性能开销。
  • maximumPoolSize : 表示最大线程数,意味着核心线程数都被用完了,那只能重新创建新的线程来执行任务,但是前提是不能超过最大线程数量,否则该任务只能进入阻塞队列进行排队等候,直到有线程空闲了,才能继续执行任务。
  • keepAliveTime : 表示线程存活时间,除了核心线程外,那些被新创建出来的线程可以存活多久。意味着,这些新的线程一但完成任务,而后面都是空闲状态时,就会在一定时间后被摧毁。
  • unit : 存活时间单位。
    workQueue : 表示任务的阻塞队列,由于任务可能会有很多,而线程就那么几个,所以那么还未被执行的任务就进入队列中排队,队列我们知道是 FIFO 的,等到线程空闲了,就以这种方式取出任务。这个一般不需要我们去实现。

2)二问:线程池创建线程的5种方法?1,2了解3,4,5重要

五种从线程池创建线程方式(1,2了解3,4,5掌握)

通过分别调用Executors类的方法实现不同类型功能的线程池,但是底层仍然是调用了ThreadPoolExecutor

ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);

ExecutorService executor = Executors.newWorkStealingPool();

ExecutorService executor = Executors.newFixedThreadPool(5);

ExecutorService executor = Executors.newSingleThreadExecutor();

ExecutorService executor = Executors.newCachedThreadPool();
①了解2

**Executors.newScheduledThreadPool(常驻核心线程数):**创建一个定长线程池,支持定时及周期性任务执行。延迟执行

在这里插入图片描述
深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第3张图片

Executors.newWorkStealingPool();java8新特性 创建一个具有抢占式操作的线程池 ForkJoinPool 类

深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第4张图片
深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第5张图片

②重要3

Executors.newFixedThreadPool(线程数): 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第6张图片

Executors.newSingleThreadExecutor(): 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第7张图片

Executors.newCachedThreadPool(): 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第8张图片
阻塞队列的学习!!!

③代码简单使用
public class ThreadPoolExecutorDemo {
    /*10个人在银行办事,银行有五个工作人员*/
    public static void main(String[] args) {
//        ExecutorService executor = Executors.newFixedThreadPool(5);
//        ExecutorService executor = Executors.newSingleThreadExecutor();
        ExecutorService executor = Executors.newCachedThreadPool();
        try {
            for (int i = 1; i <= 10; i++) {
                int finalI = i;
                executor.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "\t" + finalI);

                });
            }
        }
        finally {
            executor.shutdown();
        }
    }
}

结果:不唯一

深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第9张图片

3)三问:讲了这么多线程池创建线程的方法,你会使用哪个?使用自定义的!

一个都不用,生产中我们只使用自己定义的

为什么不用JDK帮助我们已经写好的Executor类的new方法?

生产实践与知识教育并不能一概而论

例如在linkedblockingQueue中的长度为INT_MAX大约21亿,然而现实生活中没有哪个服务器可以支撑那么多数据而安然无恙

阻塞队列BlockingQueue接口-类似食品柜

①Demo自定义线程池
public class MyselfThreadPool {
    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                2,
                5,
                1l,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

            try {
                for (int i = 1; i <= 8; i++) {
                    threadPoolExecutor.execute(() -> {
                        System.out.println("线程"+Thread.currentThread().getName() + "\t办理业务");
                    });
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }
            finally {
                threadPoolExecutor.shutdown();
            }
    }
}

结果

深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第10张图片
改变循环长度为9,结果仍然只处理了八个请求

深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第11张图片

②总结:线程池可处理的任务数=最大线程数+阻塞队列长度

当创建线程到最大线程数后,非核心线程数优先处理不在阻塞队列中的任务。

线程池可处理的任务数=最大线程数+阻塞队列长度

5.线程池七大参数

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

深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第12张图片

1)线程池的拒绝策略

当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:

项目 作用
ThreadPoolExecutor.AbortPolicy 丢弃任务并抛出RejectedExecutionException异常
ThreadPoolExecutor.CallerRunsPolicy 由调用线程(提交任务的线程)处理该任务
ThreadPoolExecutor.DiscardOldestPolicy 丢弃队列等待最久的的任务,然后重新提交当前任务
ThreadPoolExecutor.DiscardPolicy 丢弃任务,但是不抛出异常

在这里插入图片描述

6.线程池的工作流程

深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第13张图片

1.当正在运行的线程数小于常驻核心线程数时,那么会立即创建线程执行任务;

2.当正在运行的线程数大于或者等于核心线程数,那么将这个任务放入队列中;

3.当队列已满且正在运行的线程数小于最大线程数,那么还是要创建非核心线程立刻运行非队列中的任务;

4.当队列满了,且运行线程数大于或者等于最大线程数,那么就启用饱和拒绝策略来执行

7.如何合理的配置线程池参数,比如最大线程数?

①查看当前电脑配置–>CPU核心数

System.out.println(Runtime.getRuntime().availableProcessors());//我的是4核心数,一般商务本配置

②根据具体业务情况分析,CPU密集或IO密集

1)CPU密集,CPU核心数+1个线程的线程池

深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第14张图片

也就是说,我应该设置最大线程数为4+1=5
2)IO密集,①CPU核心数*2;②CPU核心数/(1-阻塞系数),阻塞系数0.8~0.9

在这里插入图片描述
深入浅出线程池ing:为何使用线程池创建线程?线程池特点,原理,七大参数,工作流程,自定义线程池,合理配置最大线程数?_第15张图片

也就是说,我可以设置最大线程数为4*2=8或者4/1-0.9=40

你可能感兴趣的:(java,队列,多线程,并发编程)