池化思想在我们的日常开并不少见,有数据库连接池、线程池、对象池、常量池等等。下面我们主要针对线程池来一步一步揭开线程池的面纱。
- 使用线程池的好处
- 1、降低资源消耗
- 可以重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 2、提高响应速度
- 当任务到达时,任务可以不需要等到线程创建就能立即执行。
- 3、提高线程的可管理性
- 线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控
谈到线程池,我们自然离不开ThreadPoolExecotor类
- ThreadPoolExecotor
ThreadPoolExecotor 有许多的构造方法,但所有的构造方法最后都调了下面的最后一个构造函数
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;
}
居然有7个参数,接下来我们就来一一分析一下参数的作用
int corePoolSize // 线程池长期维持的线程数,即使线程处于Idle状态,也不会回收。
int maximumPoolSize // 线程数的上限
long keepAliveTime // 超过corePoolSize的线程的idle时长,超过这个时间,多余的线程会被回收。
TimeUnit unit //时间单位
BlockingQueue<Runnable> workQueue // 任务的排队队列
ThreadFactory threadFactory // 新线程的产生方式
RejectedExecutionHandler handle // 拒绝策略
-
线程池的工作顺序
If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.
If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread.
If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected. -
corePoolSize -> 任务队列 -> maximumPoolSize -> 拒绝策略
-
常用工作队列
- ArrayBlockingQueue
- PriorityBlockingQueue
- LinkedBlockingQueue
- Synchronous
- DelayQueue
-
常用拒绝策略
- ThreadPoolExecutor.AbortPolicy;//丢弃任务并抛出RejectedExecutionException异常。
- ThreadPoolExecutor.DiscardPolicy;//也是丢弃任务,但是不抛出异常。
- ThreadPoolExecutor.DiscardOldestPolicy;//丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
- ThreadPoolExecutor.CallerRunsPolicy;//由调用线程处理该任务
- threadFactory:线程工厂,主要用来创建线程;
- 创建新线程时使用的工厂。如果没有另外说明,则在同一个 ThreadGroup 中一律使用 Executors.defaultThreadFactory() 创建线程,并且这些线程具有相同的 NORM_PRIORITY 优先级和非守护进程状态。通过提供不同的 ThreadFactory,可以改变线程的名称、线程组、优先级、守护进程状态,等等。如果从 newThread 返回 null 时 ThreadFactory 未能创建线程,则执行程序将继续运行,但不能执行任何任务。
三、Executors
我们可以直接使用 ThreadPoolExecotor 类创建线程池,但官方并不推荐我们怎么做,而是使用 Executors 类提供的几个静态方法来创建线程池,那我们先来分析Executors常用的几个方法。
- Executors常用方法
- newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
- newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
- newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
- 线程池的大小
通常我们线程池设置为cpu个数的倍数
参考文章:
https://www.cnblogs.com/CarpenterLee/p/9558026.html
https://www.cnblogs.com/kuoAT/p/6714762.html
https://blog.csdn.net/fuyuwei2015/article/details/72758179