线程池类型
FixedThreadPool:固定线程数量的线程池ScheduledThreadPool:支持以某种频率执行任务ForkJoinPool:把任务被递归分解成子任务fork,子任务执行完成后将结果合并join
任务队列类型
DelayQueue:无界延时队列,只有到了延时时间才会出队ArrayBlockingQueue:有界队列,基于数组实现LinkedBlockingDeque:基于链表实现,可以设置大小,默认是无界队列PriorityBlockingQueue:无界优先级队列,默认数组长度是11,内部采用了大根堆或小根堆的设计
任务拒绝策略
拒绝策略定义在ThreadPoolExecutor的内部类中
AbortPolicy:抛出异常CallerRunsPolicy:由当前提交任务的线程执行DiscardPolicy:啥也不干,不抛出异常,也不会执行任何操作DiscardOldestPolicy:丢弃队列中最老的一个,然后将当前任务提交线程池处理SynchronousQueue:队列不存储任务,新来一个任务开启一个线程,直到线程数达到最大后,触发拒绝策略
任务执行顺序
- 啥时候创建临时线程: 新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程
- 啥时候拒绝任务: 核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始任务拒绝
如何设置线程数
- CPU型任务:当前可用的处理器核数 + 1
- IO 密集型任务:当前可用的处理器核数 * 2
- 获取处理器核数:
Runtime.getRuntime().availableProcessors()
如何关闭线程池
shutdown:线程池不再接收新任务,但会执行完目前所有的任务,线程池进入SHUTDOWN状态shutdownNow:线程池会清空任务队列,同时发出中断信号,让正在执行的任务停止,停不停要看任务有没有进行中断处理,线程池进入STOP状态
如何定义线程池
-
线程池的核心就是阻塞队列,利用阻塞队列来实现线程阻塞等待去获取任务,线程池参数如下:
public ThreadPoolExecutor( int corePoolSize, // 核心线程数量,一直存在不会被回收的线程 int maximumPoolSize, // 最大线程数量,除了核心线程其他是临时线程 long keepAliveTime, // 临时线程的存活时间 TimeUnit unit, // 时间单位 BlockingQueue workQueue,// 任务队列 RejectedExecutionHandler handler // 任务处理策略 ) -
示例
public static void main(String[] args) { ThreadPoolExecutor threadPool = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 2, 64, 5L, TimeUnit.MINUTES, new LinkedBlockingQueue<>(30), new ThreadPoolExecutor.AbortPolicy() ); Future<?> future = threadPool.submit(() -> { return "success"; }); try { Object taskResult = future.get(); System.out.println("taskResult: " + taskResult); } catch (InterruptedException | ExecutionException e) { System.out.println("Task threw exception: " + e.getCause()); } }
线程池异常处理
CompletableFuture.supplyAsync(() -> { int a = 10/0; return 666; }, executor)
.exceptionally(ex -> {
System.out.printf("异常:"+ex.toString());
return -1;
})
.thenAccept(res -> {
System.out.printf("返回值:" + res);
});