1.1.7 线程池原理

为什么要用线程池

线程不是越多越好?
  1. 线程在Java中是一个对象,更是操作系统的资源,线程创建、销毁需要时间。如果创建时间+销毁时间> 执行任务时间就很不合算。

  2. Java对象占有堆内存,操作系统线程占用系统内存,根据jvm规范,一个线程默认最大栈大小1M,这个栈空间是需要从系统内存中分配的。线程越多,会消耗很多的内存

  3. 操作系统需要频繁切换线程上下文(大家都想被运行),影响性能。

线程池的推出,就是为了方便的控制线程数量。

从时间、空间、线程切换三方面去思考。

线程池原理 - 概念

  1. 线程池管理器:用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务。

  2. 工作线程:线程池中线程,在没有任务时处于等待状态,可以循环的执行任务。

  3. 任务接口:每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完成后的收尾工作,任务的执行状态等。

  4. 任务队列:用于存放没有处理的任务。提供一种缓冲机制。

截屏2020-02-13上午10.11.34.png

线程池API - 接口定义和实现类

类型 名称 描述
接口 Executor 最上层的接口,定义了执行任务的方法execute
接口 ExecutorService 继承了Executor接口,扩展了Callable、Future、关闭方法
接口 ScheduledExecutorService 继承了ExecutorService,增加了定时任务相关的方法
实现类 ThreadPoolExecutor 基础、标准的线程池实现
实现类 ScheduledThreadPoolExecutor 继承了ThreadPoolExecutor,实现了ScheduledExecutorService中相关定时任务的方法

可以认为ScheduledThreadPoolExecutor是最丰富的实现类

线程池API - 方法定义

截屏2020-02-13上午10.22.29.png

截屏2020-02-13上午10.24.30.png

线程池API - Executors工具类

截屏2020-02-13上午10.28.26.png

线程池原理 - 任务executor过程

  1. 是否达到核心线程数量?没达到,创建一个工作线程来执行任务。

  2. 工作队列是否已满? 没满,则将新提交的任务存储在工作队列里。

  3. 是否达到线程池最大数量? 没达到,则创建一个新的工作线程来执行任务。

  4. 最后,执行拒绝策略来处理这个任务。

截屏2020-02-13上午10.31.54.png

特殊的线程池信息

  1. 线程池信息: 核心线程数量5,最大数量5,无界队列,超出核心线程数量的线程存活时间:5秒

    也就是核心线程数量等于最大数量,且无界队列时,固定线程数量,超过数量的任务进入队列中等待被执行。

  2. 核心线程数量0,最大数量Integer.MAX_VALUE,SynchronousQueue队列,超出核心线程数量的线程存活时间:60秒

    直接创建需要运行任务数量的线程数量,线程存活时间60s。

    SynchronousQueue队列

    SynchronousQueue是一个内部只能包含一个元素的队列。插入元素到队列的线程被阻塞,直到另一个线程从队列中获取了队列中存储的元素。同样,如果线程尝试获取元素并且当前不存在任何元素,则该线程将被阻塞,直到线程将元素插入队列。

    将这个类称为队列有点夸大其词。这更像是一个点。

  3. 核心线程数量5,最大数量Integer.MAX_VALUE,DelayedWorkQueue延时队列,超出核心线程数量的线程存活时间:0秒

    定时执行线程池信息:3秒后执行,一次性任务,到点就执行

    Executors.newScheduledThreadPool()一样的

  • 调用shutdown后,不接收新的任务,会任务执行结束,追加的任务在线程池关闭后,无法再提交,会被拒绝执行。

    threadPoolExecutor.shutdown();

  • 调用shutdownnow后,队列中的线程不再执行,运行中的线程被终止,追加的任务在线程池关闭后,无法再提交,会被拒绝执行。

    List<Runnable> shutdownNow = threadPoolExecutor.shutdownNow();把终止的线程返回。

测试代码:

public class Demo7 {
    //测试:提交15个执行时间需要3秒的任务,看超过大小的2个,对应的处理情况
    public void testCommon(ThreadPoolExecutor threadPoolExecutor) throws InterruptedException {
        for (int i = 0 ; i < 15 ; i++){
            int finalI = I;
            threadPoolExecutor.submit(()->{
                System.out.println("开始执行,任务" + finalI);
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务" + finalI + "运行完毕");
            });
            System.out.println("任务提交成功");
        }
        // 查看线程数量,查看队列等待数量
        Thread.sleep(5000L);
        System.out.println("当前线程池线程数量为:" + threadPoolExecutor.getPoolSize());
        System.out.println("当前线程池线程等待的数量为:" + threadPoolExecutor.getQueue().size());
        // 等待15秒,查看线程数量和队列数量(理论上,会被超出核心线程数量的线程自动销毁)
        Thread.sleep(15000L);
        System.out.println("当前线程池线程数量为:" + threadPoolExecutor.getPoolSize());
        System.out.println("当前线程池线程等待的数量为:" + threadPoolExecutor.getQueue().size());
    }

     /**
     * 1、线程池信息: 核心线程数量5,最大数量10,无界队列,超出核心线程数量的线程存活时间:5秒, 指定拒绝策略的
     *
     * @throws Exception
     */
    private void threadPoolExecutor1() throws Exception{
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,10,5,TimeUnit.SECONDS,
                new LinkedBlockingQueue<>());
        testCommon(threadPoolExecutor);
    }

     /**
     * 2、 线程池信息: 核心线程数量5,最大数量10,队列大小3,超出核心线程数量的线程存活时间:5秒, 指定拒绝策略的
     *
     * @throws Exception
     */
     private void theadPoolExecutor2() throws Exception{
         ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
                 new LinkedBlockingQueue<>(3), new RejectedExecutionHandler() {
             @Override
             public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                 System.out.println("有任务被拒绝了");
             }
         });
         testCommon(threadPoolExecutor);
     }

     /**
     * 3、 线程池信息: 核心线程数量5,最大数量5,无界队列,超出核心线程数量的线程存活时间:5秒
     *
     * @throws Exception
     */
     private void threadPoolExecutor3() throws Exception{
         ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,5,5,TimeUnit.SECONDS,
                 new LinkedBlockingQueue<>());
         testCommon(threadPoolExecutor);
     }

     /**
     * 4、 线程池信息:
     * 核心线程数量0,最大数量Integer.MAX_VALUE,SynchronousQueue队列,超出核心线程数量的线程存活时间:60秒
     *
     * @throws Exception
     */
     private void threadPoolExecutor4() throws Exception{
         ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0,Integer.MAX_VALUE,60,TimeUnit.SECONDS,
                 new SynchronousQueue<>());
         testCommon(threadPoolExecutor);
     }

     /**
     * 5、 定时执行线程池信息:3秒后执行,一次性任务,到点就执行 <br/>
     * 核心线程数量5,最大数量Integer.MAX_VALUE,DelayedWorkQueue延时队列,超出核心线程数量的线程存活时间:0秒
     *
     * @throws Exception
     */
     private void threadPoolExecutor5() throws Exception{
         //和Executors.newScheduledThreadPool()是一样的
         ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
         threadPoolExecutor.schedule(()->{
             System.out.println("任务被执行,现在的时间为:" + System.currentTimeMillis());
         },3000L,TimeUnit.MILLISECONDS);
         System.out.println("任务提交成功,现在的时间为:" + System.currentTimeMillis() + "当前线程池中的线程数量" + threadPoolExecutor.getPoolSize());
     }

     /**
     * 6、 定时执行线程池信息:线程固定数量5 ,<br/>
     * 核心线程数量5,最大数量Integer.MAX_VALUE,DelayedWorkQueue延时队列,超出核心线程数量的线程存活时间:0秒
     *
     * @throws Exception
     */
     private void threadPoolExecutor6(){
         ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(5);
         threadPoolExecutor.scheduleWithFixedDelay(()->{
             System.out.println("任务被执行,现在的时间为:" + System.currentTimeMillis());
         },2000L,1000L,TimeUnit.MILLISECONDS);
         threadPoolExecutor.scheduleAtFixedRate(()->{
             System.out.println("任务被执行,现在的时间为:" + System.currentTimeMillis());
         },2000L,1000L,TimeUnit.MILLISECONDS);
     }




    public static void main(String[] args) throws Exception {
        Demo7 demo7 = new Demo7();
//        demo7.threadPoolExecutor1();
//        demo7.theadPoolExecutor2();
//        demo7.threadPoolExecutor3();
//        demo7.threadPoolExecutor4();
//        demo7.threadPoolExecutor5();
//        demo7.threadPoolExecutor6();
    }


}
发布了17 篇原创文章 · 获赞 13 · 访问量 918

猜你喜欢

转载自blog.csdn.net/weixin_43871142/article/details/104307904