JDK 里面自带了线程池的实现,相比较于我们自己编写线程类,线程池可以更好地管理线程资源.
简介
下面的图是和线程池相关的几个类之间的关系
Executors类是JDK提供的线程池工具类,里面有几个实现线程池的默认方法,可以直接调用.
- Executors.newCachedThreadPool(无界线程池,自动线程回收)
- Executors.newFixedThreadPool(固定大小的线程池);
- Executors.newSingleThreadExecutor(单一后台线程);
- 这三个方法的底层都是调用的 ThreadPoolExecutor 类的构造器实现的,所以我们也可以自己来控制线程池的各种参数,推荐自己实现.
示例代码
1.使用 Executors 工厂类来建立线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo3 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++) {
int index = i;
executorService.execute(() -> divTask(100, index));
}
executorService.shutdown();
}
private static void divTask(int a, int b) {
try {
double result = a / b;
System.out.println(result);
} catch (ArithmeticException e) {
e.printStackTrace();
System.out.println("除数不能为0!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
打印结果:
33.0
100.0
50.0
25.0
除数不能为0!
java.lang.ArithmeticException: / by zero
at com.example.springboot01.util.ThreadPoolDemo3.divTask(ThreadPoolDemo3.java:19)
at com.example.springboot01.util.ThreadPoolDemo3.lambda$main$0(ThreadPoolDemo3.java:12)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
2.使用 ThreadPoolExecutor 类定义线程池
import java.util.concurrent.*;
public class ThreadPoolDemo3 {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 2,
1000, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
for (int i = 0; i < 5; i++) {
int index = i;
threadPoolExecutor.execute(() -> divTask(100, index));
}
threadPoolExecutor.shutdown();
}
private static void divTask(int a, int b) {
try {
double result = a / b;
System.out.println(result);
} catch (ArithmeticException e) {
e.printStackTrace();
System.out.println("除数不能为0!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
打印结果:
50.0
33.0
25.0
除数不能为0!
100.0
java.lang.ArithmeticException: / by zero
at com.example.springboot01.util.ThreadPoolDemo3.divTask(ThreadPoolDemo3.java:23)
at com.example.springboot01.util.ThreadPoolDemo3.lambda$main$0(ThreadPoolDemo3.java:16)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
ThreadPoolExecutor 类构造器各参数说明
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler){}
序号 | 名称 | 类型 | 含义 |
---|---|---|---|
1 | corePoolSize | int | 核心线程池大小 |
2 | maximumPoolSize | int | 最大线程池大小 |
3 | keepAliveTime | long | 线程最大空闲时间 |
4 | unit | TimeUnit | 时间单位 |
5 | workQueue | BlockingQueue | 线程等待队列 |
6 | threadFactory | ThreadFactory | 线程创建工厂 |
7 | handler | RejectedExecutionHandler | 拒绝策略 |
这边着重讲一下最后一个参数 RejectedExecutionHandler (拒绝策略)吧.
在使用线程池的时候,如果队列满了,那么新任务添加到线程池的时候就会有问题,这个问题怎么解决,就需要 RejectedExecutionHandler (拒绝策略)上场了.
java.util.concurrent.ThreadPoolExecutor 类里面自带了4种拒绝策略,分别是:
- CallerRunsPolicy: 使用此策略,如果添加到线程池失败(线程池满了),那么主线程会自己去执行该任务,不会等待线程池中的线程去执行。
- AbortPolicy: (abort:流产)该策略是线程池的默认策略。使用该策略时,如果线程池队列满了就放弃这个任务并且抛出RejectedExecutionException异常。
- DiscardPolicy: (discard: 抛弃)这个策略是AbortPolicy的slient(沉默)版本,如果线程池队列满了,会直接放弃这个任务并且不会抛出任何异常。
- DiscardOldestPolicy: 如果队列满了,会将最早进入队列的任务删掉腾出空间,再将新任务加入队列。
参考资料
线程池之ThreadPoolExecutor概述
线程池之ThreadPoolExecutor使用
线程池的RejectedExecutionHandler(拒绝策略)