美文网首页
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阻塞的次数会减少,从而性能更高。

相关文章

  • JAVA线程池

    线程池详解 ThreadPoolExecutor ThreadPoolExecutor是最灵活的一个线程池,用户可...

  • Java 线程池详解

    Java ThreadPoolExecutor详解 ThreadPoolExecutor是Java语言对于线程池的...

  • ThreadPoolExecutor线程池的配置优化详解

    ThreadPoolExecutor线程池的一些基本知识,创建 ThreadPoolExecutor对象,这个对象...

  • java线程池详解

    参考文章:ThreadPoolExecutor使用详解参考文章:ThreadPoolExecutor线程池解析与B...

  • ThreadPoolExecutor使用详解

    1、ThreadPoolExecutor构造参数的详解 corePoolSize, // 线程池长期维持的线程数,...

  • Android 线程池原理

    线程池核心类 : ThreadPoolExecutor:提供了一系列参数来配置线程池 线程池优点: 1.重用线程池...

  • 线程池使用

    ThreadPoolExecutor 线程池 创建线程池,主要利用 ThreadPoolExecutor 这个类...

  • ThreadPoolExecutor源码解析

      无论是直接还是间接的创建线程池,归根结底都是通过ThreadPoolExecutor来创建线程池并且配置线程池...

  • Concurrent Java 06 - 线程调度

    线程池 - ThreadPoolExecutor ThreadPoolExecutor是其中功能最为强大的线程池类...

  • 线程池

    线程池简介: android提供了四种线程池,都是由直接或简介配置ThreadPoolExecutor来实现的。 ...

网友评论

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

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