当前位置:   article > 正文

线程池ThreadPoolExecutor 的使用_threadpoolexecutor使用

threadpoolexecutor使用
线程池创建的七大参数:
        1、corePoolSize线程池核心线程数量,核心线程不会被回收,即使没有任务执行,也会保持空闲状态。如果线程池中的线程少于此数目,则在执行任务时创建。
        2、maximumPoolSize:当线程数量达到corePoolSize,且workQueue队列塞满任务了之后,继续创建线程,但不能超过 maximumPoolSize。
        3、keepAliveTime:超过corePoolSize之后的“临时线程”的存活时间。
        4、unit:keepAliveTime的单位。
        5、workQueue:当线程数超过corePoolSize时,新的任务会处在等待状态,并存在workQueue中,BlockingQueue是一个先进先出的阻塞式队列实现,workQueue有以下几种实现:

            (1)、ArrayBlockingQueue  基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。

           (2)、LinkedBlockingQuene基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而不会去创建新线程直到maxPoolSize,因此使用该工作队列时,参数maxPoolSize其实是不起作用的。

          (3)、SynchronousQuene一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。

          (4)、PriorityBlockingQueue 具有优先级的无界阻塞队列,优先级通过参数Comparator实现。

           ArrayBlockingQueue和PriorityBlockingQueue一般很少使用

        6、threadFactory:创建线程的工厂类,通常我们会自定义一个threadFactory设置线程的名称,这样我们就可以知道线程是由哪个工厂类创建的,可以快速定位。
        7、handler:线程池执行拒绝策略,当线程数量达到maximumPoolSize大小,并且workQueue也已经塞满了任务的情况下,线程池会调用handler拒绝策略来处理请求。

ThreadPoolExecutor 的使用示例:
public class HelloThreadPool {
    static class Task implements Runnable {
        private int i;

        public Task(int i) {
            this.i = i;
        }

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " Task " + i);
            try {
                System.in.read();
                //TimeUnit.MILLISECONDS.sleep(500);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public String toString() {
            return "Task{" +
                    "i=" + i +
                    '}';
        }
    }

    public static void main(String[] args) {
        ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 5,
                5, TimeUnit.SECONDS,    //5 秒內沒有任务要处理,非核心线程释放掉
                /**队列中最多能存入的任务数量
                 *   当所有的核心线程都在处理任务的时候,新进来的任务将放入队列中,如果队列中放满了,则新建额外的线程处理,总线程数量不能超过maximumPoolSize
                 */
                new ArrayBlockingQueue<Runnable>(4),
                Executors.defaultThreadFactory(),//  默认的线程工厂,通过 new Thread 产生线程
                /**四个拒绝策略:
                 * AbortPolicy:为线程池默认的拒绝策略,该策略直接抛异常处理。
                 * DiscardPolicy:直接抛弃不处理。
                 * DiscardOldestPolicy:丢弃队列中最老的任务。
                 * CallerRunsPolicy:将任务分配给当前执行 execute 的方法线程来处理,如这个调用方法中表示 main方法主线程。
                 */
                new ThreadPoolExecutor.CallerRunsPolicy());

        //创建10个线程,核心线程限制性,然后放入等待队列,等待队列放满后再新建线程
        for (int i = 0; i < 10; i++) {
            tpe.execute(new Task(i));
        }

        System.out.println(tpe.getQueue());

        tpe.execute(new Task(100));

        System.out.println(tpe.getQueue());

        tpe.shutdown();
    }

        线程在使用过程中新创建的值会放在threadLocalMap中,threadLocalMap是以threadlocal作为键、value作为值来存储的,对于普通线程当线程执行结束后线程被销毁、threadLocalMap也随之被清空;

        但是对于线程池,线程执行完成后thread并不会被销毁,会将threadlocal置为空来保证同一个thread执行不同任务的数据安全,但是threadlocal被置为空后value还在,等到新的任务执行时也会产生threadLocalMap,不断的累计这些value值可能会导致内存溢出;

        线程池防止内存溢出的解决办法是执行完一个任务后调用threadlocal的remove方法,清空这些value值;    

线程池的源码解读:

       从上面代码中的 tpe.execute(new Task(i)) 点进去:

addWorker方法解读:

可参考:【精选】线程池的设计与原理解析(三)之---addWorker()方法-CSDN博客

       

        然后是创建一个任务线程,并将线程放入任务队列中,更新线程池中线程数量,如果添加到线程池失败则移除线程、线程数量减1

线程执行方法 runWorker 说明:

        线程通过while从任务队列中获取任务执行,一直到没有可执行任务(线程池中没有任务或线程池执行了关闭方法)或执行任务出现异常跳出while循环,然后执行finally中的processWorkerExit方法,processWorkerExit 有两种逻辑异常退出和正常退出;

             异常退出:线程执行过程中出现异常,更新可用线程数减1 ,在线程池中移除这个线程,然后在最后再添加一个线程到线程池中

             正常退出:没有可执行任务,先移除这个线程,然后判断线程池中的线程数是否大于核心线程数,如果不满足则创建一个新的线程到线程池中

      线程本身没有是否核心线程这个属性,只要线程没有可执行任务时就会调用processWorkerExit方法,然后就会被销毁,线程池中最后也只会保留核心数量的线程,而不管这些线程是刚开始的核心线程还是后面新建的线程;

getTask方法说明:
       poll方法阻塞一定时间
       take方法一直阻塞      
processWorkerExit方法说明:

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/1008816
推荐阅读
相关标签
  

闽ICP备14008679号