线程池

作者: 念䋛 | 来源:发表于2020-12-29 10:01 被阅读0次

    线程是调度CPU资源的最小单位,线程模型分为KLT模型和ULT模型,Java采用的是KLT模型,java线程与OS(内核)线程保持1:1的映射关系,就是java创建一个线程,内核与之相对应的也会创建一个线程

    image.png

    线程池的介绍
    在并发请求数量多的情况下,而且每个线程的执行时间很短,毫秒级就会执行结束,这样就会频繁的创建和销毁线程,降低了效率,可能出现创建和销毁线程的时间要大于线程执行的时间,线程池的出现就是为了解决上述的问题.
    使用场景(绝大多数的场景)
    线程执行时间短
    线程要处理的任务数多
    线程池的优势
    重用已有的线程,减少创建和销毁线程
    提高相应速度,当任务到达时,不需等待直接使用已有的线程,反应快
    提高线程的可管理性,线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行同意的分配,调优的监控.

    Java 线程池的创建
    Java 创建线程池非常重要的类ThreadPoolExecutor其中有4个构造函数,但是最终调用的是7个参数的构造函数

    public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler) {
            if (corePoolSize < 0 ||
                maximumPoolSize <= 0 ||
                maximumPoolSize < corePoolSize ||
                keepAliveTime < 0)
                throw new IllegalArgumentException();
            if (workQueue == null || threadFactory == null || handler == null)
                throw new NullPointerException();
            this.corePoolSize = corePoolSize;
            this.maximumPoolSize = maximumPoolSize;
            this.workQueue = workQueue;
            this.keepAliveTime = unit.toNanos(keepAliveTime);
            this.threadFactory = threadFactory;
            this.handler = handler;
        }
    

    7个参数
    int corePoolSize, 核心线程数
    int maximumPoolSize, 最大线程数 = 非核心线程数 + 核心线程数
    long keepAliveTime, 最大允许线程不干活的时间,超过时间则销毁线程,其实就是获取阻塞队列的等待时间,如果在这段时间队列中没有放入新的任务,那当先的线程就会终止,其实就是跳出了while循环, 后续会分析到
    TimeUnit unit, keepAliveTime的时间单位
    BlockingQueue<Runnable> workQueue, 存放任务数队列
    ThreadFactory threadFactory, 线程创建工厂
    RejectedExecutionHandler handler 拒绝策略

    image.png

    线程池的5中状态
    ctl变量包含了两个信息,一个是运行状态,一个是线程池的线程数,整型共32位,其中高3位为运行状态,其余29位为线程数

    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;
    private static int runStateOf(int c)     { return c & ~CAPACITY; }//当前运行状态
    private static int workerCountOf(int c)  { return c & CAPACITY; }//当前线程数
    private static int ctlOf(int rs, int wc) { return rs | wc; }//通过状态和线程生成ctl
    
    

    下面的图片根据高3位可以得出
    RUNNING 111
    SHUTDOWN 000
    STOP 001
    TIDYING 010
    TERMINATED 011


    image.png
    image.png
    image.png

    拒绝策略
    new ThreadPoolExecutor.AbortPolicy ();//抛出异常


    image.png

    new ThreadPoolExecutor.DiscardPolicy (); //什么也没做


    image.png
    new ThreadPoolExecutor.DiscardOldestPolicy ();//将队列中队头的的任务poll出来,不做处理,就是丢弃掉了
    image.png
    new ThreadPoolExecutor.CallerRunsPolic();//当前提交任务的线程直接执行,不交给线程池来执行(比如tomcat的线程再执行线程池的execute方法,被拒绝,当使用此拒绝策略时,tomcat的线程直接执行任务)
    image.png
    image.png

    看上图可知,如果使用CallerRunsPolic策略,那么main线程就执行了此任务

    相关文章

      网友评论

        本文标题:线程池

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