美文网首页
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 线程池原理

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