java线程池源码解读
Posted hfstudyself
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java线程池源码解读相关的知识,希望对你有一定的参考价值。
java线程池的顶级类是Executors 内置了几种线程池
1、newFixedThreadPool 并且重载了两个此方法 有固定线程数的线程池 当达到设置的线程数时 多余的任务会排队,当处理完一个马上就会去接着处理排队中的任务
源码如下
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
下面的 newFixedThreadPool 比第一个多了一个线程工厂
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); }
都会最终返回一个 ThreadPoolExecutor对象 这个才是线程池的核心类 ThreadPoolExecutor继承了 AbstractExecutorService抽象类 AbstractExecutorService实现ExecutorService接口 所以返回的是
ExecutorService 类型 (此处用到了设计模式中适配器模式中的接口适配器模式,有兴趣的同学可以去了解一下,在这不赘述)
下面分析核心线程类 ThreadPoolExecutor 下面是源码
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
corePoolSize : 核心线程数,一旦创建将不会再释放。如果创建的线程数还没有达到指定的核心线程数量,将会继续创建新的核心线程,直到达到最大核心线程数后,核心线程数将不在增加;如果没有空闲的核心线程,同时又未达到最大线程数,则将继续创建非核心线程;如果核心线程数等于最大线程数,则当核心线程都处于激活状态时,任务将被挂起,等待空闲线程来执行。
maximumPoolSize : 最大线程数,允许创建的最大线程数量。如果最大线程数等于核心线程数,则无法创建非核心线程;如果非核心线程处于空闲时,超过设置的空闲时间,则将被回收,释放占用的资源。
keepAliveTime : 也就是当线程空闲时,所允许保存的最大时间,超过这个时间,线程将被释放销毁,但只针对于非核心线程。
unit : 时间单位,TimeUnit.SECONDS等。
workQueue : 任务队列,存储暂时无法执行的任务,等待空闲线程来执行任务。
threadFactory : 线程工程,用于创建线程。
handler : 当线程边界和队列容量已经达到最大时,用于处理阻塞时的程序
解释一下 workQueue 任务队列 workQueue 有三种类型 newFixedThreadPool 默认使用 LinkedBlockingQueue
1.1 有界的任务队列(ArrayBlockingQueue)
(1) 创建队列时,指定队列的最大容量。
(2) 若有新的任务要执行,如果线程池中的线程数小于corePoolSize,则会优先创建新的线程。若大于corePoolSize,则会将新任务加入到等待队列中。
(3) 若等待队列已满,无法加入。如果总线程数不大于线程数最大值maximumPoolSize,则创建新的线程执行任务。若大于maximumPoolSize,则执行拒绝策略。
1.2 无界的任务队列(LinkedBlockingQueue)
(1) 与有界队列相比,除非系统资源耗尽,否则不存在任务入队失败的情况。
(2) 若有新的任务要执行,如果线程池中的线程数小于corePoolSize,线程池会创建新的线程。若大于corePoolSize,此时又没有空闲的线程资源,则任务直接进入等待队列。
(3) 当线程池中的线程数达到corePoolSize后,线程池不会创建新的线程。
(4) 若任务创建和处理的速度差异很大,无界队列将保持快速增长,直到耗尽系统内存。
(5) 使用无界队列将导致在所有 corePoolSize 线程都忙时,新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize(因此,maximumPoolSize 的值也就无效了)。当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
1.3 优先任务队列(PriorityBlockingQueue)
(1) 带有执行优先级的队列。是一个特殊的无界队列。
(2) ArrayBlockingQueue和LinkedBlockingQueue都是按照先进先出算法来处理任务。而PriorityBlockingQueue可根据任务自身的优先级顺序先后执行(总是确保高优先级的任务先执行)。
详细解读一下 LinkedBlockingQueue 可以传入队列长度 默认是Integer的最大值
简单的贴出核心的方法
public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); // Note: convention in all put/take/etc is to preset local var // holding count negative to indicate failure unless set. int c = -1; Node<E> node = new Node<E>(e); final ReentrantLock putLock = this.putLock; final AtomicInteger count = this.count; putLock.lockInterruptibly(); try { /* * Note that count is used in wait guard even though it is * not protected by lock. This works because count can * only decrease at this point (all other puts are shut * out by lock), and we (or some other waiting put) are * signalled if it ever changes from capacity. Similarly * for all other uses of count in other wait guards. */ while (count.get() == capacity) { notFull.await(); } enqueue(node); c = count.getAndIncrement(); if (c + 1 < capacity) notFull.signal(); } finally { putLock.unlock(); } if (c == 0) signalNotEmpty(); }
此方法是插入队列中线程 生成线程时E类型必须是 Runnable 类型
由于篇幅关系 这次只解读 常用到的 newFixedThreadPool固定线程池 。
以上是关于java线程池源码解读的主要内容,如果未能解决你的问题,请参考以下文章