Java多线程学习之线程池源码详解
1 public ThreadPoolExecutor(int corePoolSize, 2 int maximumPoolSize, 3 long keepAliveTime, 4 TimeUnit unit, 5 BlockingQueue<Runnable> workQueue) { 6 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, 7 Executors.defaultThreadFactory(), defaultHandler); 8 } 9 10 public ThreadPoolExecutor(int corePoolSize, 11 int maximumPoolSize, 12 long keepAliveTime, 13 TimeUnit unit, 14 BlockingQueue<Runnable> workQueue, 15 ThreadFactory threadFactory) { 16 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, 17 threadFactory, defaultHandler); 18 } 19 20 public ThreadPoolExecutor(int corePoolSize, 21 int maximumPoolSize, 22 long keepAliveTime, 23 TimeUnit unit, 24 BlockingQueue<Runnable> workQueue, 25 RejectedExecutionHandler handler) { 26 this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, 27 Executors.defaultThreadFactory(), handler); 28 } 29 30 public ThreadPoolExecutor(int corePoolSize, 31 int maximumPoolSize, 32 long keepAliveTime, 33 TimeUnit unit, 34 BlockingQueue<Runnable> workQueue, 35 ThreadFactory threadFactory, 36 RejectedExecutionHandler handler) { 37 if (corePoolSize < 0 || 38 maximumPoolSize <= 0 || 39 maximumPoolSize < corePoolSize || 40 keepAliveTime < 0) 41 throw new IllegalArgumentException(); 42 if (workQueue == null || threadFactory == null || handler == null) 43 throw new NullPointerException(); 44 this.corePoolSize = corePoolSize; 45 this.maximumPoolSize = maximumPoolSize; 46 this.workQueue = workQueue; 47 this.keepAliveTime = unit.toNanos(keepAliveTime); 48 this.threadFactory = threadFactory; 49 this.handler = handler; 50 }
参数介绍:
- maximumPoolSize:线程池的最大线程数量,表示在线程池中最多可以创建多少个线程。当缓存队列已满时候,新提交的任务会创建新的线程执行,直到线程池中达到maximumPoolSize个线程。
- unit:存活时间的单位,有如下单位:
1 TimeUnit.DAYS; //天 2 TimeUnit.HOURS; //小时 3 TimeUnit.MINUTES; //分钟 4 TimeUnit.SECONDS; //秒 5 TimeUnit.MILLISECONDS; //毫秒 6 TimeUnit.MICROSECONDS; //微妙 7 TimeUnit.NANOSECONDS; //纳秒
- workQueue:阻塞队列,用于暂时存放任务,有如下几种:
ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;
- threadFactory:线程工厂,指定创建线程的策略。
- handler:当任务无法被及时处理和存放时候,进行处理的策略。比如说,线程池已满并且阻塞队列已满,新提交的任务需要被进行其他处理。有如下的处理方案:
// 29 private static final int COUNT_BITS = Integer.SIZE - 3; // 由28个1二进制组成的数字 private static final int CAPACITY = (1 << COUNT_BITS) - 1; // runState is stored in the high-order bits private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS; // Packing and unpacking ctl private static int runStateOf(int c) { return c & ~CAPACITY; }
阻塞队列的操作可分为如下:
抛异常响应 | 特值响应 | 阻塞响应 | 超时响应 | |
---|---|---|---|---|
插入 | add(o) |
offer(o) |
put(o) |
offer(o,timeout,timeunit) |
移除 | remove(o) |
poll(o) |
take(o) |
poll(timeout,timeunit) |
检查 | element(o) |
peek(o) |
- 抛异常响应:如果该操作不能立即满足,则抛出异常。
- 特值响应:如果该操作不能立即执行,则返回一个特值,如 false或null响应。
- 阻塞响应:如果该操作不能立即执行,则会阻塞等待直到满足执行条件。
- 超时响应:如果该操作不能立即执行,则等待一定时间,在该时间内满足条件则执行,否则返回一个特值相应是否执行成功。
BlockingQueue 的实现类:
1 // 构造函数 2 public ArrayBlockingQueue(int capacity, boolean fair) { 3 if (capacity <= 0) 4 throw new IllegalArgumentException(); 5 this.items = new Object[capacity]; 6 lock = new ReentrantLock(fair); 7 // 空条件、满条件 8 notEmpty = lock.newCondition(); 9 notFull = lock.newCondition(); 10 } 11 //插入函数 12 public void put(E e) throws InterruptedException { 13 checkNotNull(e); 14 final ReentrantLock lock = this.lock; 15 // 可中断的锁 16 lock.lockInterruptibly(); 17 try { 18 while (count == items.length) 19 notFull.await(); 20 enqueue(e); 21 } finally { 22 // 解锁 23 lock.unlock(); 24 } 25 }
阻塞队列的选择策略:
1.newFixedThreadPool
- 简介
newFixedThreadPool将创建一个固定长度的线程池,每当提交一个任务,创建一个线程,直到达到线程池的最大数量,这时线程池的规模不再变化,如果某个线程中途应为Exception 异常结束,线程池会再补一个线程加入线程池。
- 源码分析
1 public static ExecutorService newFixedThreadPool(int nThreads) { 2 return new ThreadPoolExecutor(nThreads, nThreads, 3 0L, TimeUnit.MILLISECONDS, 4 new LinkedBlockingQueue<Runnable>()); 5 } 6 7 public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory){ 8 return new ThreadPoolExecutor(nThreads, nThreads, 9 0L, TimeUnit.MILLISECONDS, 10 new LinkedBlockingQueue<Runnable>(), 11 threadFactory); 12 }
可以看到,newFixedThreadPool 的 核心池大小和线程池最大大小一致,就是说,该线程池大小在接受任务时,就逐步创建线程到最大值。
1 public void allowCoreThreadTimeOut(boolean value) { 2 // 如果keepAliveTime 为0或小于0,则不能设置核心池自动死亡 3 if (value && keepAliveTime <= 0) 4 throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); 5 if (value != allowCoreThreadTimeOut) { 6 allowCoreThreadTimeOut = value; 7 if (value) 8 interruptIdleWorkers(); 9 } 10 }
2. newCachedThreadPool
- 简介
newCachedThreadPool 将创建一个可缓存的线程池,如果线程池的当前规模超过了处理需求时,将回收空闲线程,而当需求增加时,则可以添加新的线程,线程池的规模没有限制。
- 源码分析
1 public static ExecutorService newCachedThreadPool() { 2 return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 3 60L, TimeUnit.SECONDS, 4 new SynchronousQueue<Runnable>()); 5 } 6 7 public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { 8 return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 9 60L, TimeUnit.SECONDS, 10 new SynchronousQueue<Runnable>(), 11 threadFactory); 12 }
核心池大小设置为0,线程池的最大大小设置为“无穷大”,说明该线程池没有处于核心池的线程,即,所有线程池的所有线程都是会超时死亡的。线程空闲存活时间为60秒,意味着如果线程空闲60秒就会被杀死。阻塞队列使用了SynchronousQueue队列 ,提交的任务不会暂存到队列中,而是又改队移交到线程直接执行。
- 分析
它提供比固定大小的线程池更好的排队性能、如果任务请求过于频繁,导致任务提交速度大于线程请求速度,可能会使应用程序创建大量的线程导致性能下降甚至奔溃。所以,如果限制当前任务的数量足以满足资源管理的需求,优先选择有界队列。
3. newSingleThreadExecutor
- 简介
newSingleThreadExecutor 是一个单线程的 Executor,它创建单个工作者线程来执行任务,如果该线程异常结束,将创建一个新的线程来代替它。newSingleThreadExecutor 能确保任务依照队列中的顺序来串行执行(例如,FIFO,LIFO,优先级等)。
- 源码分析
1 public static ExecutorService newSingleThreadExecutor() { 2 return new FinalizableDelegatedExecutorService 3 (new ThreadPoolExecutor(1, 1, 4 0L, TimeUnit.MILLISECONDS, 5 new LinkedBlockingQueue<Runnable>())); 6 } 7 8 public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory){ 9 return new FinalizableDelegatedExecutorService 10 (new ThreadPoolExecutor(1, 1, 11 0L, TimeUnit.MILLISECONDS, 12 new LinkedBlockingQueue<Runnable>(), 13 threadFactory)); 14 }
核心池和线程池最大大小皆为1,说明该线程池只能容纳一个线程,0毫秒的存活时间,说明该线程不会自动死亡。使用无边界的LinkedBlockingQueue阻塞队列,无法及时处理的任务可能会无限制的堆积在该阻塞队列中,可能造成内存泄漏。
4. newScheduledThreadPool
- 简介
newScheduledThreadPool 创建一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似Timmer。
- 源码分析
1 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { 2 return new ScheduledThreadPoolExecutor(corePoolSize); 3 } 4 public static ScheduledExecutorService newScheduledThreadPool( 5 int corePoolSize, ThreadFactory threadFactory) { 6 return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); 7 } 8 // 使用了 DelayedWorkQueue 阻塞队列 9 public ScheduledThreadPoolExecutor(int corePoolSize, 10 ThreadFactory threadFactory) { 11 super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, 12 new DelayedWorkQueue(), threadFactory); 13 }
可以看到 newScheduledThreadPool 返回了一个 ScheduledExecutorService 对象,和之前三个返回的 ExecutorService 不一样。使用了DelayedWorkQueue作为阻塞队列,定时执行。ScheduledThreadPoolExecutor 方法:
1 // 延迟执行,只会执行一次 2 public ScheduledFuture<?> schedule(Runnable command, 3 long delay, TimeUnit unit); 4 // 延期定时执行,重复执行多次 5 public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, 6 long initialDelay, 7 long period, 8 TimeUnit unit);