ThreadPoolExecutor作用以及原理解析

1.线程池出现的原因:

     在多线程的情况下,多个线程在创建和销毁的阶段会消费很多时间,占有很多资源,线程池为了减少在创建和销毁的资源下出现:

2.JAVA中的ThreadPoolExecutor线程池

2.1 线程池的运行方式

        当线程池中获取到一个需要执行的线程的时候,是如何运行的呢?

       此处可以通过对源码的查看了解:

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))//执行addWorker,会创建一个核心线程,如果创建失败,重新获取ctl
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) { //表示线程池为running状态,切队列可以添加任务
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command)) //线程池不是running状态 则将线程从队列中移除  并执行对应策略
                reject(command);
            else if (workerCountOf(recheck) == 0)//如果移除失败,则会判断工作线程是否为0 ,如果过为0 就创建一个非核心线程
                addWorker(null, false);
        }
        else if (!addWorker(command, false))//若队列已满 并且不能再线程池中创建线程
            reject(command);
    }

其中 private boolean addWorker(Runnable firstTask, boolean core)中的参数分别为任务,和对应是否为核心线程

具体方案如下:

     获取到一个执行的任务,首先判断当前运行的线程数是否小于核心线程数,表示核心线程是否有空闲,若有则创建核心线程或是在核心线程中执行。若添加任务成功则直接退出该方法,否则继续。

     当核心线程都已经被占用,判断等待队列是否满了,如果没满,则将其加入等待队列,如果满了 则判断是否超过线程池的最大容量线程数,若超过则直接进行对应的策略,若没有则创建线程执行任务。

 

    附加:workQueue的offer表示往队列(队列部分可先往下查看在返回看具体实现)中添加,若能往队列中添加则返回true,否则返回false

    具体的实现是通过addWorker。

    isRunning(c)表示线程池的状态是RUNNING

  

 

2.2 线程池的构造函数

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 

上述为ThreadPoolExecutor的核心构造函数,其他构造函数都是调用该构造函数执行。

参数解释:

1.corePoolSize   表示线程池中的核心线程个数,什么是核心线程?表示在线程池中创建完以后就不会销毁的线程。

2.maximumPoolSize  表示线程池中最大容量的线程数

3.keepAliveTime  线程池中除了核心线程,其他线程都是有存活时间的,表示其他线程的存活时间(表示其他线程的最大空闲的时间)

4.unit:  计算时间的单位

5.workQueue: 等待队列,用于存储等待执行的线程,FIFO原则。

6.threadFactory  表示创建线程的工厂

7.handler  拒绝策略,在线程等待队列满了之后,且线程池的中的线程个数大于等于maximumPoolSize,执行某些策略。

 

workQueue

     常用的等待队列有哪些?

      ArrayBlockingQueue:表示一个有界队列,其构造函数必须指定队列的大小(采用的是加锁的机制 实现对队列中添加元素或删除元素)

如:public ArrayBlockingQueue(int capacity),public ArrayBlockingQueue(int capacity, boolean fair),ArrayBlockingQueue(int capacity, boolean fair,Collection<? extends E> c)

       LinkedBlockingQueue:直接调用 new LinkedBlockingQueue<Runnable>()情况下,是为一个无界队列,但亦可以指定队列的大小。与ArrayBlockingQueue其他的不同就相当于ArrayList和LinkedList的区别。(采用的是加锁的机制 实现对队列中添加元素或删除元素)

       在jdk自带的Executors工厂构建一个newSingleThreadExecutor等方法 都是调用了new LinkedBlockingQueue<Runnable>()

具体参考https://mp.csdn.net/editor/html/111346385

threadFactory 

      通过对源码发现,只需是实现创建线程的方法,在创建线程池默认情况下,如果没有传入参数threadFactory的时候,会调用Executors工厂下的默认线程池方法

  将线程的优先级都设置为普通优先级

 

handler 

       线程池中提供了4种策略:

      1.CallerRunsPolicy  直接调用r.run();的方法(直接执行任务 不启用新线程)执行任务

       2.AbortPolicy   不执行新任务,并抛出异常

       3.DiscardPolice:直接抛弃该任务,不抛弃任何异常

       4.DiscardOldestPolicy 将线程池队列中最老的等待任务抛弃,然后执行e.execute(r);(线程池执行任务的方法)  

       5.若想要通过自己的设置策略实现则通过实现接口 RejectedExecutionHandler即可。

   

 

 

   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值