「Java 路线」| 线程池

2020-12-30  本文已影响0人  彭旭锐

点赞关注,不再迷路,你的支持对我意义重大!

🔥 Hi,我是丑丑。本文 「Java 路线」| 导读 —— 他山之石,可以攻玉 已收录,这里有 Android 进阶成长路线笔记 & 博客,欢迎跟着彭丑丑一起成长。(联系方式在 GitHub)


前言


目录


1. 前置知识

这篇文章的内容会涉及以下前置 / 相关知识,贴心的我都帮你准备好了,请享用~


2. 线程池概述

2.1 为什么要使用线程池?

2.2 线程池如何实现线程复用?

线程执行完任务之后,调用阻塞队列BlockingQueue#take()出队操作,当阻塞队列非空时,则继续执行任务;当阻塞队列为空时,则当前队列阻塞。

2.3 提交任务

向线程池提交任务可以使用 execute() & submit(),区别如下:

2.4 关闭线程池

shutdown() / shutdownNow()

线程中断协作机制

2.5 阿里巴巴编程规范

根据《阿里巴巴 Java 开发手册》,线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。


3. 线程池相关类

Executor
ExecutorService
AbstractExecutorService
ThreadPoolExecutor
ScheduledExecutorService
ScheduledThreadPoolExecutor


4. 线程池参数

ThreadPoolExecutor.java

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    ...
}
参数 描述
1、int corePoolSize 核心线程数
2、int maximunPoolSize 最大线程数
3、long keepAliveTime 线程空闲最大存活时间
4、BlockingQueue workQueue 阻塞队列
5、ThreadFactory threadFactory 线程工厂
6、RejectedExecutionHandler handler 拒绝策略

Executors.java

namePrefix = "pool-" + poolNumber.getAndIncrement() +  "-thread-";
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);

6、RejectedExecutionHandler handler

public interface RejectedExecutionHandler {
    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

线程池提供了以下 4 种拒绝策略:

拒绝策略 描述
AbortPolicy 抛出 RejectedExecutionException 异常(默认)
CallerRunsPolicy 直接在调用线程执行
DiscardOldestPolicy 丢弃阻塞队列中队首的任务
DiscardPolicy 直接丢弃当前任务

5. 线程池工作机制

为什么先将任务加入阻塞队列,而不是线程池满了再加入阻塞队列?


6. 如何合理配置线程池?

线程池的配置需要根据「任务特性」选择不同的任务配置,因地制宜。主要从以下角度分析:

为什么 CPU 密集型线程池经验值为 Ncpu + 1?

在操作系统中,会将磁盘的一部分空间划分为虚拟内存(读写速度慢),当 CPU 需要访问的数据在虚拟内存上时,当前线程就进入了 “页缺失” 状态,需要等待数据从磁盘调度到真实内存才会唤醒。为了防止出现 “页缺失” 时,CPU 空闲出来,保证任意时刻 CPU 都不会空闲,可以选择 + 1;

提示: 调用 Runtime.getRuntime().availableProcessors() 获得可用的核心数。

需要区分任务优先级,则使用 PriorityBlockingQueue;

执行时间不同的任务可以交给不同规模的线程池来处理,或者可以使用优先级队列,让执行时间短的任务先执行;

无界队列没有限制队列元素个数,有可能有造成资源耗尽。


创作不易,你的「三连」是丑丑最大的动力,我们下次见!

上一篇 下一篇

猜你喜欢

热点阅读