美文网首页
线程池查漏补缺

线程池查漏补缺

作者: xhrg | 来源:发表于2019-01-25 10:34 被阅读0次

    tomcat线程池和jdk线程池区别

    概述

    1. 线程池是什么,为什么要线程池
    2. jdk有哪些线程池和原理
    3. 第三方中间件的线程池特点
    • tomcat线程池
    • quartz线程池
    1. 线程池展望

    线程池是什么,为什么要线程池

    我们在项目启动后,因为CPU是多核的,为了充分利用CPU,可能需要启动多个线程去处理任务。频繁的创建销毁线程是有开销的。所以需要创建线程后缓存住,让线程可以频繁的处理各种任务。这个时候就需要用线程池。线程池一般会缓存住N个线程,然后往线程池里面扔任务Runnable,线程不断的处理任务。处理完了后停留在那里等待。

    jdk有哪些线程池和原理

    jdk线程池主要入口是在java.util.concurrent.Executors,其中包含

    • Executors.newFixedThreadPool 固定核心数的线程池,有多余任务往无界队列中放

    • Executors.newSingleThreadExecutor 单线程的线程池,有多余任务往无界队列中放

    • Executors.newCachedThreadPool 有任务来就开辟新的线程,不缓存任务,不缓存线程。

    • Executors.newSingleThreadScheduledExecutor 单线程的延迟线程池,也就是说可以指定任务N秒后周期性执行。

    • Executors.newScheduledThreadPool N线程的延迟线程池,也就是说可以指定任务N秒后周期性执行。
      * 这个线程池内部依赖于ScheduledThreadPoolExecutor,队列依赖于ScheduledThreadPoolExecutor.DelayedWorkQueue,这个队列在take的时候,会根据你添加任务的时候的时间做一个awaitNanos(delay),代码见该类的take方法。故而实现了延迟执行。

    • Executors.unconfigurableExecutorService

    线程池的主要原理是在ThreadPoolExecutor这个类中。ThreadPoolExecutor有以下概念

    • corePoolSize

    • maximumPoolSize

    • keepAliveTime

    • workQueue

    这四个概念一起解释,corePoolSize指的是线程池核心数,当有任务进来的时候,如果开辟的线程少于该值,就不断开新线程去处理,直到该值。如果到了该值之后,就把新的任务存放在队列中,也就是workQueue中,去存放的过程会成功和失败,如果成功就存放在队列中了,如果失败,就继续开辟线程去执行。直到线程数等于maximumPoolSize,便不再开新线程。如果队列满了,线程也到最大值了,这个时候,就进行拒绝策略。

    • AbortPolicy 默认策略,抛出异常RejectedExecutionException。

    • DiscardPolicy 什么都不做

    • DiscardOldestPolicy 把任务头丢掉,然后再把任务加入队列

    • CallerRunsPolicy 主线程自己去执行任务

    • RejectHandler 自己实现

    原理大致说明。ThreadPoolExecutor这个类除了参数那些参数外,还有HashSet<Worker> workers,参数,该参数和线程一一对应,也就是说线程池里面的线程就是worker,当任务进来后会和corePoolSize比较,继而新建或者申请worker。新建的线程会不断的从任务队列去拿任务,拿任务有超时时间,就是刚才说到的keepAliveTime,到达时间后,如果说当前线程数大于corePollSize,则自己退出该线程。没有大于则继续循环运行,继续循环运行就是在死循环中去拿队列。

    第三方中间件的线程池特点

    tomcat线程池

    tomcat的线程池是StandardThreadExecutor类,该类的属性也是ThreadPoolExecutor,不过是把ThreadPoolExecutor动态设置参数暴露出来了。所以StandardThreadExecutor类可以动态的修改核心数,最大数。并且该类的阻塞队列使用的是继承自LinkedBlockingQueue的TaskQueue。TaskQueue的核心在于,只要运行当前池子的线程小于maximumPoolSize,就拒绝你加入队列。我们知道线程的数量和IO密集有关系,tomcat这种IO密集型的中间件,适合更多的线程。这里的线程数是maxThreads,该值默认200,tomcat可以配置。

    public boolean offer(Runnable o) {
           //这个类是TaskQueue的的方法,我们知道,线程池,是先加入队列,失败后再开线程直到max数。
            if (parent==null) return super.offer(o);
            // 若运行线程为最大线程数,说明线程已经最大了,没办法,还是扔队列吧。
            if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
            //若任务数小于线程数,直接扔队列,扔队列后,那些闲着的线程自然会取。没必要返回false,让其再重开线程。
            if (parent.getSubmittedCount()<(parent.getPoolSize())) return super.offer(o);
            // 发现运行线程数少于池最大线程数,拒绝加入队列,让线程池继续开线程。
            if (parent.getPoolSize()<parent.getMaximumPoolSize()) return false;
            //if we reached here, we need to add it to the queue
            return super.offer(o);
        }
    

    quartz线程池

    quartz线程池是在org.quartz.simpl.SimpleThreadPool

    该线程池非常简单,初始化的时候新建N个线程。这个线程是在线程池初始化的时候就新建。然后把线程放在availWorkers中,如果有任务进来,就从availWorkers拿出1个线程放进busyWorkers,然后把任务给该线程执行。执行完了之后返回给availWorkers中。如果线程满了,主线程扔任务的时候,会检查availWorkers的size,当size<1的时候,停半秒继续检查availWorkers直到有可用才运行任务。

    线程池展望

    相关文章

      网友评论

          本文标题:线程池查漏补缺

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