线程池:3大方法、7大参数、4种拒绝策略
线程池的好处:
- 降低资源的消耗
- 提高响应速度
- 方便统一管理
线程复用、可以控制最大并发数、管理线程
线程池:3大方法

- Executors.newSingleThreadExecutor();//单个线程
- Executors.newFixedThreadPool(5);//创建一个固定大小的线程池
- Executors.newCachedThreadPool();//可伸缩的,遇强则强,遇弱则弱
public class TestPool1 {
public static void main(String[] args) {
//ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
//ExecutorService threadPool = Executors.newFixedThreadPool(5);//创建一个固定大小的线程池
ExecutorService threadPool = Executors.newCachedThreadPool();//可伸缩的,遇强则强,遇弱则弱
try {
for (int i = 0; i < 10; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"->OK");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池用完,程序结束,关闭线程池
threadPool.shutdown();
}
}
}
下面从7大参数种分析为什么不用Executors创建线程池
7大参数
源码分析:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, //约为21亿,容易造成OOM
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
本质:三大方法底层都是调用的ThreadPoolExecutor(...)
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;
}
可以发现ThreadPoolExecutor(...)有7个参数
- int corePoolSize/ /核心线程池大小
- int maximumPoolSize //最大线程池大小
- long keepAliveTime //超时了没有人调用就会释放
- TimeUnit unit //超时单位
- BlockingQueue<Runnable> workQueue //阻塞队列
- ThreadFactory threadFactory //线程工厂
-
RejectedExecutionHandler handler //拒绝策略
图片.png
可以发现:通过Executors创建的newCachedThreadPool(...)的最大线程池数为Integer.MAX_VALUE, //约为21亿,容易造成OOM
用ThreadPoolExecutor创建线程池:(用的时默认的拒绝策略)
public static void test2(){
//自定义线程池。工作中用ThreadPoolExecutor
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy() //默认的拒绝策略:如果阻塞队列满了,将不会处理新进来的线程,并报错。
);
try {
//最大承载:maximumPoolSize+ Queue
//当大于最大承载时会报错
for (int i = 0; i < 8; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"->OK");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池用完,程序结束,关闭线程池
threadPool.shutdown();
}
}
四种拒绝策略:

-
AbortPolicy():
默认的拒绝策略:如果阻塞队列满了,将不会处理新进来的线程,并报错。(代码如上) - CallerRunsPolicy() :
//用拒绝策略----CallerRunsPolicy()创建线程池
public static void test3(){
//自定义线程池。工作中用ThreadPoolExecutor
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy() //哪来的去哪里
);
try {
//最大承载:maximumPoolSize+ Queue
for (int i = 0; i < 9; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"->OK");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池用完,程序结束,关闭线程池
threadPool.shutdown();
}
}
***********结果***********
pool-1-thread-1->OK
main->OK
pool-1-thread-1->OK
pool-1-thread-1->OK
pool-1-thread-1->OK
pool-1-thread-2->OK
pool-1-thread-3->OK
pool-1-thread-4->OK
pool-1-thread-5->OK
可以发现:第9个线程通过main线程执行的,
只要线程池未关闭,该策略直接在调用者线程(main线程)中运行当前被丢弃的任务。显然这样不会真的丢弃任务,但是,调用者线程性能可能急剧下降。
- DiscardOldestPolicy():
//用拒绝策略----DiscardOldestPolicy()创建线程池
public static void test5(){
//自定义线程池。工作中用ThreadPoolExecutor
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,新来的线程会尝试去和最早的线程竞争
);
try {
//最大承载:maximumPoolSize+ Queue
for (int i = 0; i < 10; i++) {
final int temp = i;
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"--->"+temp+"->OK");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池用完,程序结束,关闭线程池
threadPool.shutdown();
}
}
结果不一定:队列满了,新来的线程会尝试去和最早的线程竞争,竞争不过就会被抛弃。
- DiscardPolicy():
//用拒绝策略----DiscardPolicy()创建线程池
public static void test4(){
//自定义线程池。工作中用ThreadPoolExecutor
ExecutorService threadPool = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardPolicy() //队列满了就会丢掉新来的任务,但是不会抛出异常
);
try {
//最大承载:maximumPoolSize+ Queue
for (int i = 0; i < 10; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"->OK");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池用完,程序结束,关闭线程池
threadPool.shutdown();
}
}
**************结果:******************
pool-1-thread-1->OK
pool-1-thread-2->OK
pool-1-thread-2->OK
pool-1-thread-2->OK
pool-1-thread-2->OK
pool-1-thread-3->OK
pool-1-thread-4->OK
pool-1-thread-5->OK
可以发现队列满了后剩余的2个线程被抛弃
小结:
最大线程池大小如何设置(maximumPoolSize ):
- 1、CPU密集型
电脑为几核,那么maximumPoolSize 就定义为几。这样可以保证CPU的效率最高
//最大线程如何选择:
//1、CPU密集型:电脑是几核,那么maximumPoolSize就为几
public static void test6(){
//获取CPU的核数
int processors = Runtime.getRuntime().availableProcessors();
//自定义线程池。工作中用ThreadPoolExecutor
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
2,
processors,
3,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy() //队列满了,新来的线程会尝试去和最早的线程竞争
);
try {
//最大承载:maximumPoolSize+ Queue
for (int i = 0; i < 10; i++) {
final int temp = i;
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"--->"+temp+"->OK");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池用完,程序结束,关闭线程池
threadPool.shutdown();
}
}
- 2、IO密集型
因为IO十分消耗资源,因此一般先判断程序中十分耗IO的线程有多少(比如为10个);那么设置maximumPoolSize 就要 > 10。一般设置maximumPoolSize 为耗IO线程数量的两倍。避免系统阻塞
网友评论