mirror of
https://github.com/Snailclimb/JavaGuide
synced 2025-06-16 18:10:13 +08:00
[docs update&fix]添加并发面试问题:如何设计一个能够根据任务的优先级来执行的线程池?& 修复一些笔误
This commit is contained in:
parent
42b4eb6726
commit
b2ae0fde18
@ -19,7 +19,7 @@ tag:
|
||||
|
||||
我们可以把消息队列看作是一个存放消息的容器,当我们需要使用消息的时候,直接从容器中取出消息供自己使用即可。由于队列 Queue 是一种先进先出的数据结构,所以消费消息时也是按照顺序来消费的。
|
||||
|
||||

|
||||

|
||||
|
||||
参与消息传递的双方称为 **生产者** 和 **消费者** ,生产者负责发送消息,消费者负责处理消息。
|
||||
|
||||
|
@ -142,7 +142,7 @@ icon: jianli
|
||||
|
||||
项目介绍尽量压缩在两行之内,不需要介绍太多,但也不要随便几个字就介绍完了。
|
||||
|
||||
|
||||
另外,个人收获和项目成果都是可选的,如果选择写的话,也不要花费太多篇幅,记住你的重点是介绍工作内容/个人职责。
|
||||
|
||||
**2、技术架构直接写技术名词就行,不要再介绍技术是干嘛的了,没意义,属于无效介绍。**
|
||||
|
||||
|
@ -700,7 +700,7 @@ CompletableFuture.runAsync(() -> {
|
||||
|
||||
### 合理组合多个异步任务
|
||||
|
||||
正确使用 `thenCompose()` 、 `thenCombine()` 、``acceptEither()`、`allOf()`、`anyOf() `等方法来组合多个异步任务,以满足实际业务的需求,提高程序执行效率。
|
||||
正确使用 `thenCompose()` 、 `thenCombine()` 、`acceptEither()`、`allOf()`、`anyOf() `等方法来组合多个异步任务,以满足实际业务的需求,提高程序执行效率。
|
||||
|
||||
实际使用中,我们还可以利用或者参考现成的异步任务编排框架,比如京东的 [asyncTool](https://gitee.com/jd-platform-opensource/asyncTool) 。
|
||||
|
||||
@ -708,7 +708,7 @@ CompletableFuture.runAsync(() -> {
|
||||
|
||||
## 后记
|
||||
|
||||
这篇文章只是简单介绍了 `CompletableFuture` 比较常用的一些 API 。如果想要深入学习的话,还可以多找一些书籍和博客看,比如下面几篇文章就挺不错:
|
||||
这篇文章只是简单介绍了 `CompletableFuture` 的核心概念和比较常用的一些 API 。如果想要深入学习的话,还可以多找一些书籍和博客看,比如下面几篇文章就挺不错:
|
||||
|
||||
- [CompletableFuture 原理与实践-外卖商家端 API 的异步化 - 美团技术团队](https://tech.meituan.com/2022/05/12/principles-and-practices-of-completablefuture.html):这篇文章详细介绍了 `CompletableFuture` 在实际项目中的运用。参考这篇文章,可以对项目中类似的场景进行优化,也算是一个小亮点了。这种性能优化方式比较简单且效果还不错!
|
||||
- [读 RocketMQ 源码,学习并发编程三大神器 - 勇哥 java 实战分享](https://mp.weixin.qq.com/s/32Ak-WFLynQfpn0Cg0N-0A):这篇文章介绍了 RocketMQ 对`CompletableFuture`的应用。具体来说,从 RocketMQ 4.7 开始,RocketMQ 引入了 `CompletableFuture`来实现异步消息处理 。
|
||||
|
@ -484,6 +484,35 @@ CPU 密集型简单理解就是利用 CPU 计算能力的任务比如你在内
|
||||
- **[Hippo4j](https://github.com/opengoofy/hippo4j)**:异步线程池框架,支持线程池动态变更&监控&报警,无需修改代码轻松引入。支持多种使用模式,轻松引入,致力于提高系统运行保障能力。
|
||||
- **[Dynamic TP](https://github.com/dromara/dynamic-tp)**:轻量级动态线程池,内置监控告警功能,集成三方中间件线程池管理,基于主流配置中心(已支持 Nacos、Apollo,Zookeeper、Consul、Etcd,可通过 SPI 自定义实现)。
|
||||
|
||||
### 如何设计一个能够根据任务的优先级来执行的线程池?
|
||||
|
||||
这是一个常见的面试问题,本质其实还是在考察求职者对于线程池以及阻塞队列的掌握。
|
||||
|
||||
我们上面也提到了,不同的线程池会选用不同的阻塞队列作为任务队列,比如`FixedThreadPool` 使用的是`LinkedBlockingQueue`(无界队列),由于队列永远不会被放满,因此`FixedThreadPool`最多只能创建核心线程数的线程。
|
||||
|
||||
假如我们需要实现一个优先级任务线程池的话,那可以考虑使用 `PriorityBlockingQueue` (优先级阻塞队列)作为任务队列(`ThreadPoolExecutor` 的构造函数有一个 `workQueue` 参数可以传入任务队列)。
|
||||
|
||||

|
||||
|
||||
`PriorityBlockingQueue` 是一个支持优先级的无界阻塞队列,可以看作是线程安全的`PriorityQueue`,两者底层都是使用小顶堆形式的二叉堆,即值最小的元素优先出队。不过,`PriorityQueue` 不支持阻塞操作并且是有界的。
|
||||
|
||||
要想让 `PriorityBlockingQueue` 实现对任务的排序,传入其中的任务必须是具备排序能力的,方式有两种:
|
||||
|
||||
1. 提交到线程池的任务实现 `Comparable` 接口,并重写 `compareTo` 方法来指定任务之间的优先级比较规则。
|
||||
2. 创建 `PriorityBlockingQueue` 时传入一个 `Comparator` 对象来指定任务之间的排序规则(推荐)。
|
||||
|
||||
不过,这存在一些风险和问题,比如:
|
||||
|
||||
- `PriorityBlockingQueue` 是无界的,可能堆积大量的请求,从而导致 OOM。
|
||||
- 可能会导致饥饿问题,即低优先级的任务长时间得不到执行。
|
||||
- 由于需要对队列中的元素进行排序操作,因此会降低性能。
|
||||
|
||||
对于 OOM 这个问题的解决比较简单粗暴,就是继承`PriorityBlockingQueue` 并重写一下 `offer` 方法(入队)的逻辑,当插入的元素数量超过指定值就返回 false 。
|
||||
|
||||
饥饿问题这个可以通过优化设计来解决(比较麻烦),比如等待时间过长的任务会被移除并重新添加到队列中,但是优先级会被提升。
|
||||
|
||||
对于性能方面的影响,是没办法避免的,毕竟需要对任务进行排序操作。并且,对于大部分业务场景来说,这点性能影响是可以接受的。
|
||||
|
||||
## Future
|
||||
|
||||
### Future 类有什么用?
|
||||
|
@ -100,7 +100,7 @@ AOP 之所以叫面向切面编程,是因为它的核心思想就是将横切
|
||||
|
||||
OOP 不能很好地处理一些分散在多个类或对象中的公共行为(如日志记录、事务管理、权限控制、接口限流、接口幂等等),这些行为通常被称为 **横切关注点(cross-cutting concerns)** 。如果我们在每个类或对象中都重复实现这些行为,那么会导致代码的冗余、复杂和难以维护。
|
||||
|
||||
AOP 可以将横切关注点(如日志记录、事务管理、权限控制、接口限流、接口幂等等)从**核心业务逻辑(core concerns,核心关注点)**中分离出来,实现关注点的分离。
|
||||
AOP 可以将横切关注点(如日志记录、事务管理、权限控制、接口限流、接口幂等等)从 **核心业务逻辑(core concerns,核心关注点)** 中分离出来,实现关注点的分离。
|
||||
|
||||

|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user