美文网首页
ThreadPoolExecutor线程池的配置优化详解

ThreadPoolExecutor线程池的配置优化详解

作者: 楼兰King | 来源:发表于2021-01-08 11:06 被阅读0次

    ThreadPoolExecutor线程池的一些基本知识,创建

    ThreadPoolExecutor对象,这个对象是管理线程池的

    image

    下面是工作流程,看图容易理解,所以可以看到 核心线程池跟队列都满了,最大线程池没满的话就是创建新的线程,最大的都满了,则会执行饱和策略。基本是什么没满用什么


    image.png

    饱和策略

    image
    还有一个自定义的策略,这个有很多资料 
    
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
         if (!e.isShutdown()) {
              while (e.getQueue().remainingCapacity() == 0);
              e.execute(r);
         }
     }
    remainingCapacity接口,主线程只要不断获取空余个数,是0就继续获取,直到不是0为止,这个方法不错。
    
    我测试了10万级最快是3秒,如果一个线程执行完任务需要一秒,则10万级会是1分30秒。
    
    /**
     * @Description:线程池管理类
     **/
    
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class MyThreadPoolManager {
        /**
         * 说明:下面这些常量是根据AsyncTask的源码配置的,大家可以根据自己需求自行配置
         */
        //根据cpu的数量动态的配置核心线程数和最大线程数
        private static final int CPU_COUNT         = Runtime.getRuntime().availableProcessors();
        //核心线程数 = CPU核心数 + 1
        private static final int CORE_POOL_SIZE    = CPU_COUNT + 1050;
        //线程池最大线程数 = CPU核心数 * 2 + 1
        private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 100000;
        //非核心线程闲置时间 = 超时1s
        private static final int KEEP_ALIVE        = 1;
    
        // 要确保该类只有一个实例对象,避免产生过多对象消费资源,所以采用单例模式
        private MyThreadPoolManager() {
        }
    
        private static MyThreadPoolManager sInstance;
    
        public synchronized static MyThreadPoolManager getsInstance() {
            if (sInstance == null) {
                sInstance = new MyThreadPoolManager();
            }
            return sInstance;
        }
    
        // 线程池的对象
        private ThreadPoolExecutor executor;
    
        // 使用线程池,线程池中线程的创建完全是由线程池自己来维护的,我们不需要创建任何的线程
        // 我们所需要做的事情就是往这个池子里面丢一个又一个的任务
        public void execute(Runnable r) {
            if (executor == null) {
                /**
                 * corePoolSize:核心线程数
                 * maximumPoolSize:线程池所容纳最大线程数(workQueue队列满了之后才开启)
                 * keepAliveTime:非核心线程闲置时间超时时长
                 * unit:keepAliveTime的单位
                 * workQueue:等待队列,存储还未执行的任务
                 * threadFactory:线程创建的工厂
                 * handler:异常处理机制
                 */
                executor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
                        KEEP_ALIVE, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());
            }
            try {
                executor.execute(r);// 把一个任务丢到了线程池中
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public void cancel(Runnable r) {
            if (r != null) {
                executor.getQueue().remove(r);//把任务移除等待队列
            }
        }
    }
    
    然后是线程类
    /**
     * @Description:线程类
     **/
    public class MyThread implements Runnable{
    
        public void run() {
            long time = System.currentTimeMillis();
            System.out.println("开始启动线程  ssss"+ Thread.currentThread().getId());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getId()+" 线程结束  dddd  time:"+(System.currentTimeMillis()-time));
        }
    }
    
    再然后是测试类
    /**
     * @Description:测试类
     **/
    public class Atest {
    
        @Test
        public  void te()throws Exception {
            System.out.println(Thread.currentThread().getId()+" 2222222 enter time:" + System.currentTimeMillis());
    
            MyThreadPoolManager myThreadPoolManager=MyThreadPoolManager.getsInstance();
            for (int i=0;i<100000;i++){
                MyThread myThread=new MyThread();
                myThreadPoolManager.execute(myThread);
            }
    
            System.out.println("3333leave time:" + System.currentTimeMillis());
            Thread.sleep(100000); // 因为junit结束会结束jvm,所以让它等会异步线程
        }
    }
    
    
    ArrayBlockingQueue 和 LinkedBlockingQueue 对比
    ArrayBlockingQueue和LinkedBlockingQueue都支持blockingQueue的概念,就存取block,可以说两者很相像,那么具体有哪些区别呢?
    
    内部存储
    ArrayBlockingQueue 内部是实例化一个Object数组来存储
    LinkedBlockingQueue 内部是一个内部静态类Node,维护本身的内容和next一个link.
    容量和性能
    这里做了简单的测试,和看了源码和相关作者回复的邮件。
    
    占用内存来讲。从表面来看,array会小一点,Node比较大一点。但是作者说只有不太会array比node的可能。只有在array超过1/2, 1/3的时候才可能出现。
    
    性能。在源码注释中,提到ArrayBlockingQueue支持一个是否对wait的线程进行排序,然后FIFO,这个有点消耗,但默认是没有这个工作的。然后在LinkedBlockingQueue中说Linked based queues经常会比array based queues性能高一点,但是不像array那样容易预测结果。然后ArrayBlockingQueue中维护一个锁,LinkedBlockingQueue中维护两个锁,这样Linked阻塞的次数会减少,从而性能更高。
    

    相关文章

      网友评论

          本文标题:ThreadPoolExecutor线程池的配置优化详解

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