Java线程池
ThreadPoolExecutor
在Java中可以创建的线程池类有很多,各自拥有不同的特性,但查看源码可以发现,这些线程池的创建在底层都调用了new ThreadPoolExecutor(),因此我们首先讨论ThreadPoolExecutor。
1 public ThreadPoolExecutor(int corePoolSize, 2 int maximumPoolSize, 3 long keepAliveTime, 4 TimeUnit unit, 5 BlockingQueue<Runnable> workQueue, 6 ThreadFactory threadFactory, 7 RejectedExecutionHandler handler)
| 参数类型 | 参数名 | 含义 |
| int | corePoolSize | 核心线程数量 |
| int | maximumPoolSize | 最大线程数量 |
| long | keepAliveTime | 线程最大空闲时间 |
| TimeUnit | unit | 存活时间的计量单位 |
| BlockingQueue<Runnable> | workQueue | 用于存放Runnable任务的阻塞队列 |
| ThreadFactory | threadFactory | 线程创建工厂 |
| RejectedExecutionHandler | handler | 拒绝策略 |
线程池创建后,初始线程数量为0,通过调用execute(Runnable command)来创建线程对象执行任务。
创建任务主要流程
1.判断线程池中线程的数量是否小于corePoolSize,如果小于则创建一个新的线程执行任务,否则进行下一步判断。
2.判断workQueue中是否还有空间存放Runnable任务,如果有则加入workQueue,否则进行下一步判断。
3.判断线程池中线程的数量是否小于maximumPoolSize,如果小于则创建一个新的线程执行任务,否则执行拒绝策略。
第2步和第3步判断前会先判断是否有空闲线程,有的话直接交给空闲线程(不确定)。而线程空闲后也会主动执行workQueue中的任务。
当线程池中的一个线程空闲时间超过了keepAliveTime,会判断线程池中线程的数量是否大于corePoolSize,如果大于的话,该线程会被销毁,否则不会。
了解了ThreadPoolExecutor后,就可以根据不同线程池类底层调用构造方法的参数,去判断这些线程池的特性。
CachedThreadPool
1 public static ExecutorService newCachedThreadPool() { 2 return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 3 60L, TimeUnit.SECONDS, 4 new SynchronousQueue<Runnable>()); 5 }
从以上参数可以看到,核心线程数量为0,因此进入第2步,如果没有空闲线程,应加入阻塞队列,而SynchronousQueue是一种特殊的没有容量的阻塞队列,因此进入第3步,如果没有空闲线程,则创建一个新的线程执行任务,由于maximumPoolSize为Integer.MAXVALUE,因此可以理解为是“无限”容量的线程池。
当线程空闲时间超过60秒时,会被销毁。
特点:不会有长时间存放的空闲的核心线程,没有等待的概念,有线程就用,没线程就创建,可创建“无限”数量的线程。
FixedThreadPool
1 public static ExecutorService newFixedThreadPool(int nThreads) { 2 return new ThreadPoolExecutor(nThreads, nThreads, 3 0L, TimeUnit.MILLISECONDS, 4 new LinkedBlockingQueue<Runnable>()); 5 }
从以上参数可以看到,核心线程数量和最大线程数量都是指定的n,LinkedBlockingQueue又是无界阻塞队列,所以当线程数量小于n时,优先创建线程,当线程数量等于n时,如果此时没有空闲线程,所有任务都会进入阻塞队列,只能等待空闲线程来执行。
线程最大空闲时间是0毫秒,实际没有影响,因为最大线程数量等于核心线程数量,而核心线程又是不会被销毁的,所以一旦线程数量达到n,就不会再创建也不会再销毁。
特点:线程数量最多只会等于n,并且达到n后不会再创建和销毁,没有线程执行时,所有任务都会进入无界阻塞队列等待执行。

浙公网安备 33010602011771号