从0到1深入理解JAVA线程池

2021-12-17 12:57:01 浏览数 (2)

Executors实现关系图

线程池核心思想

线程是由工作线程、缓存队列组成的一个协作流程,缓存队列一直接收数据,工作线程一直处在从队列中取数据、处理数据。

JDK1.8线程池剖析

那么缓存队列多大?工作线程多少?不够该怎么办?这个是非常值得研究,下面我们来看看java内置的集中线程池是怎么样对这几个参数进行配置的。

1、ThreadPoolExecutor

newFixedThreadPool(int nThreads):工作线程数和最大线程数相同,也就是工作线程一直都是一样的线程池,同时这个缓存队列是非常的大size=Integer.MAX_VALUE

代码语言:txt复制
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

/**
 * Creates a {@code LinkedBlockingQueue} with a capacity of
 * {@link Integer#MAX_VALUE}.
 */
public LinkedBlockingQueue() {
    this(Integer.MAX_VALUE);
}

newSingleThreadExecutor():创建一个只有一个工作线程的线程池

代码语言:txt复制
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

newCachedThreadPool():初始化工作线程数为0,最大线程数为Integer.MAX_VALUE的线程池

代码语言:txt复制
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

2、ForkJoinPool

newWorkStealingPool(int parallelism):将一个大任务拆成parallelism小任务进行执行

代码语言:txt复制
public static ExecutorService newWorkStealingPool(int parallelism) {
    return new ForkJoinPool
        (parallelism,
         ForkJoinPool.defaultForkJoinWorkerThreadFactory,
         null, true);
}

3、ScheduledThreadPoolExecutor

newSingleThreadScheduledExecutor():初始一个工作线程的定时线程池,最大线数为Integer.MAX_VALUE的线程池

代码语言:txt复制
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}

结束语

从上面常用的线程池来看的,jdk默认的线程池要么就是缓存队列特别大,要么就是最大线程数特别大,这种会导致一些极端情况,因为线程和缓存都是要消耗资源的,所以一般我们在实践过程中都会自己新建一个线程池来合理设置线程数和缓存队列大小,可参考:

代码语言:txt复制
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.acc = System.getSecurityManager() == null ?
            null :
            AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

0 人点赞