资讯专栏INFORMATION COLUMN

源码解析Executors.newFixedThreadPool(int)

source / 1846人阅读

摘要:创建一个线程池,具有固定线程数,运行在共享的无界队列中。固定线程数源码如下是的实现类。线程池中允许最大的线程数。如果线程数超过了核心线程数,过量的线程在关闭前等待新任务的最大时间。处理因为线程边界和队列容量导致的堵塞。

1.Executors.newFixedThreadPool(int nThreads):创建一个线程池,具有固定线程数,运行在共享的无界队列中。在大多数时候,线程会主动执行任务,当所有的线程都在执行任务时,有新的任务加入进来,就会进入等待队列(可以有源源不断的任务加入进来,因为是无界队列),当有空闲的线程,等待队列中的任务就会被执行。如果有线程在执行过程中因为执行失败要关闭,新创建的线程会替失败的线程执行接下来的任务。如果想要关闭这个线程池,可以调用ExecutorService的shutDown方法。

nThreads 固定线程数

源码如下:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue());
}

2.ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue):是ExecutorService的实现类。

corePoolSize 核心线程数,即使是空闲的时候,线程池中也会保留线程的数量。如果设置allowCoreThreadTimeOut为true,会使用keepAliveTime作为等待工作时间,默认为false。

maximumPoolSize 线程池中允许最大的线程数。

keepAliveTime 如果线程数超过了核心线程数,过量的线程在关闭前等待新任务的最大时间。

unit keepAliveTime 参数的时间单元。

workQueue 用来存放等待执行的任务,这些任务是通过execute方法提交的Runnable任务。

源码如下:

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

3.ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

threadFactory 用来创建新线程的工厂。

handler 处理因为线程边界和队列容量导致的堵塞。

源码如下:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue 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;
}

4.LinkedBlockingQueue:Executors.newFixedThreadPool()使用基于链表结点的无界队列LinkedBlockingQueue存储待执行的任务。继承了AbstractQueue类,实现了BlockingQueue接口,采用先进先出的排列方式,头结点是入队时间最长的元素,尾结点是入队时间最短的元素。新结点添加到队尾,从队头弹出结点。链表队列的特点是:跟基于数组的队列相比有更大的吞吐量,但在大多并发应用中性能会比较差。LinkedBlockingQueue可以在创建的时候传递一个容量参数,限制队列的长度,不设定的情况下,默认是Integer.MAX_VALUE。在没有超过队列边界的情况下,每次添加会自动创建链表结点。

源码如下:

 public LinkedBlockingQueue() {
    this(Integer.MAX_VALUE);
}
public LinkedBlockingQueue(int capacity) {
    if (capacity <= 0) throw new IllegalArgumentException();
    this.capacity = capacity;
    last = head = new Node(null);
}

5.DefaultThreadFactory:返回默认的线程工厂创建新线程。执行器Executor在同一个线程组中创建所有新的线程。如果存在SecurityManager,就使用SecurityManager的线程组,否则使用当前线程的线程组。每一个新创建的线程作为非守护线程,其优先级设置为Thread.NORM_PRIORITY和线程组允许的最大优先级的较小者。可以通过Thread.getName()获取线程的名称,形式如:pool-N-thread-M,N表示线程工厂的序列号,M表示线程工厂创建的线程的序列号。

源码如下:

public static ThreadFactory defaultThreadFactory() {
    return new DefaultThreadFactory();
}
static class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                      poolNumber.getAndIncrement() +
                     "-thread-";
    }

    ......
}

6.AbortPolicy:默认的拒绝执行处理器。抛出一个RejectedExecutionException。

源码如下:

private static final RejectedExecutionHandler defaultHandler =
    new AbortPolicy();
 public static class AbortPolicy implements RejectedExecutionHandler {
    public AbortPolicy() { }
    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        throw new RejectedExecutionException("Task " + r.toString() +
                                             " rejected from " +
                                             e.toString());
    }
}

7.例子

@Test
public void testFixedDemo01() {
    ExecutorService executorService = Executors.newFixedThreadPool(4);
    for(int i = 0;i < 10;i++) {
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " "  +" 走啦");
            }
        });
    }
}

运行结果:

核心线程数和最大线程数都是4,创建了一个线程工厂。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/71077.html

相关文章

  • 追踪解析 ThreadPoolExecutor 源码

    摘要:的前位数用来表示线程的数量,后面三位用来表示线程池的状态。线程池的状态有五种,分别是,根据单词就能猜出大概。并且为了考虑性能问题,线程池的设计没有使用悲观锁关键字,而是大量使用了和机制。 零 前期准备 0 FBI WARNING 文章异常啰嗦且绕弯。 1 版本 JDK 版本 : OpenJDK 11.0.1 IDE : idea 2018.3 2 ThreadPoolExecutor ...

    gaomysion 评论0 收藏0
  • 线程池,这一篇或许就够了

    摘要:创建方法最大线程数即源码单线程化的线程池有且仅有一个工作线程执行任务所有任务按照指定顺序执行,即遵循队列的入队出队规则创建方法源码还有一个结合了和,就不介绍了,基本不用。 *本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 为什么用线程池 创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率 >例如: > >记创建线程消耗时间T1,执行...

    UsherChen 评论0 收藏0
  • 线程池源码分析

    摘要:线程池的作用线程池能有效的处理多个线程的并发问题,避免大量的线程因为互相强占系统资源导致阻塞现象,能够有效的降低频繁创建和销毁线程对性能所带来的开销。固定的线程数由系统资源设置。线程池的排队策略与有关。线程池的状态值分别是。 线程池的作用 线程池能有效的处理多个线程的并发问题,避免大量的线程因为互相强占系统资源导致阻塞现象,能够有效的降低频繁创建和销毁线程对性能所带来的开销。 线程池的...

    enda 评论0 收藏0
  • Java线程池架构(一)原理和源码解析

    摘要:在前面介绍的文章中,提到了关于线程池的创建介绍,在文章之系列外部中第一部分有详细的说明,请参阅文章中其实说明了外部的使用方式,但是没有说内部是如何实现的,为了加深对实现的理解,在使用中可以放心,我们这里将做源码解析以及反馈到原理上,工具可 在前面介绍JUC的文章中,提到了关于线程池Execotors的创建介绍,在文章:《java之JUC系列-外部Tools》中第一部分有详细的说明,请参...

    wthee 评论0 收藏0
  • 美团面试题:Java-线程池 ThreadPool 专题详解

    摘要:去美团面试,问到了什么是线程池,如何使用,为什么要用以下做个总结。二线程池线程池的作用线程池作用就是限制系统中执行线程的数量。真正的线程池接口是。创建固定大小的线程池。此线程池支持定时以及周期性执行任务的需求。 去美团面试,问到了什么是线程池,如何使用,为什么要用,以下做个总结。关于线程之前也写过一篇文章《高级面试题总结—线程池还能这么玩?》 1、什么是线程池:  java.util...

    enrecul101 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<