线程池

线程池

三大方法

我们先看使用Executors创建的三种线程池

1
2
3
Executors.newSingleThreadExecutor();//创建一个只有一个线程的线程池
Executors.newFixedThreadPool();//创建一个固定数目的线程的线程池
Executors.newCachedThreadPool();//缓存池,会复用之前使用过的线程

执行线程

1
2
3
4
5
6
7
8
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
executorService.execute(()->{
System.out.println(Thread.currentThread().getName());
});
}
}

七大参数

阿里巴巴规范中有这么一条

1
2
3
4
5
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors返回的线程池对象的弊端如下:
1)FixedThreadPool和SingleThreadPool:
  允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
2)CachedThreadPool:
  允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。

我们来看看创建这三种线程池的构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
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);
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}

可以发现,这三个构造方法创建的对象其实都是ThreadPoolExecutor对象,只不过就是构造参数不一样。

参数 作用
int corePoolSize 核心线程池的大小
int maximumPoolSize 最大线程池的大小
long keepAliveTime 超时时间过后就释放
TimeUnit unit 超时时间单位
BlockingQueue< Runnable> workQueue 阻塞队列
ThreadFactory threadFactory 线程工厂,创建线程的,一般不用动
RejectedExecutionHandler handler 拒绝策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}

corePoolSize为一直开着的线程数,当workQueue已经满了,则继续开启线程直到maximumPoolSize,当线程数到了maximumPoolSize,然后workQueue也满了,如果还有新的任务,则使用handler拒绝策略对其进行处理。

当corePoolSize-maximumPoolSize区间的线程等待了workQueue时间后,还是没任务来,则关闭该区间的线程

1
2
3
4
5
6
7
8
9
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);

CPU密集型和IO密集型

最大线程数到底如何定义?

CPU密集型

几核CPU就是几,可以保证效率最高

1
Runtime.getRuntime().availableProcessors()//动态获取cpu核数
IO密集型

程序里面有多少个非常消耗IO的线程,一般最大线程数设置为该数字的两倍

四大拒绝策略

AbortPolicy

不处理此任务,并且抛出异常

CallerRunsPolicy

不处理此任务,往上传递此任务,哪来的回哪里去

DiscardOldestPolicy

不处理此任务,不会抛出异常

DiscardPolicy

尝试和最老的那一个线程竞争,不会抛出异常

给作者买杯咖啡吧~~~