美文网首页
1.1.7 线程池原理

1.1.7 线程池原理

作者: 叶凯飞 | 来源:发表于2020-02-13 12:39 被阅读0次

为什么要用线程池

线程不是越多越好?
  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();
    }


}

相关文章

  • 1.1.7 线程池原理

    为什么要用线程池 线程不是越多越好? 线程在Java中是一个对象,更是操作系统的资源,线程创建、销毁需要时间。如果...

  • 面试题2019年7月

    线程池原理 参考:Java 线程池原理分析 线程池工作原理:1、线程数量小于 corePoolSize,直接创建新...

  • 1.1.7 线程池应用及实现原理剖析

    为什么要使用线程池 线程在java中是一个对象,更是操作系统的资源,一个线程的创建、销毁占用很大的系统资源,使用线...

  • 源码分析AsyncTask的工作原理

    一、AsyncTask原理介绍 AsyncTask的实现原理 = 线程池+ Handler 其中:线程池用于线程调...

  • 一文搞懂Java线程池原理之ThreadPoolExecutor

    在工作中,我们经常使用线程池,但是你真的了解线程池的原理吗?同时,线程池工作原理和底层实现原理也是面试经常问的考题...

  • 万字长文:带你透彻理解“线程池”

    目标 【理解】线程池的基本概念 【理解】线程池工作原理 【掌握】自定义线程池 【应用】java内置线程池 【应用】...

  • 分析Java线程池Callable任务执行原理

    Java并发编程源码分析系列: 分析Java线程池的创建 分析Java线程池执行原理 上一篇分析了线程池的执行原理...

  • 线程池

    JDK线程池 为什么要用线程池 线程池为什么这么设计 线程池原理 核心线程是否能被回收 如何回收空闲线程 Tomc...

  • [第三篇]深入学习线程池之优雅的关闭线程池

    通过 《深入学习线程池之线程池简介及工作原理》、《深入学习线程池之通过ThreadPoolExecutor创建线程...

  • Java 线程池基础

    1. 线程池 1.1 线程池思想 线程容器,限制线程的数量 线程的复用,避免频繁的创建和销毁 1.2 线程池原理 ...

网友评论

      本文标题:1.1.7 线程池原理

      本文链接:https://www.haomeiwen.com/subject/cfvkfhtx.html