1. 项目管理认证的价值本质
在技术快速迭代的今天,项目管理专业人士资格认证(PMP)和计算机技术与软件专业技术资格(软考)的含金量正经历着前所未有的审视。作为从业十余年的项目管理老兵,我见证过无数同行在这两个认证上的投入与回报。要回答"是否值得考"这个问题,我们首先需要穿透认证本身的表象,理解其底层价值逻辑。
项目管理本质上是一门实践学科,其核心价值体现在三个方面:方法论体系、思维框架和沟通语言。以PMP为例,它系统化整理了项目启动、规划、执行、监控和收尾五大过程组,以及范围、进度、成本等十大知识领域。这种结构化认知的价值,就像给从业者配备了一套标准化的"思维操作系统"。
关键认知:认证考试最大的价值不在于证书本身,而在于系统化构建专业认知框架的过程。这就像健身房的会员卡,真正改变体型的不是那张卡片,而是持续的训练过程。
2. AI对项目管理领域的实际影响
2.1 自动化工具的边界
当前AI在项目管理中的应用主要集中在三个方面:
- 进度预测(如基于历史数据的工期估算)
- 风险识别(通过自然语言处理分析项目文档)
- 资源优化(利用算法进行人力/物资调度)
但AI的局限性同样明显。在需求冲突调解、跨部门利益协调、团队士气管理等"软技能"领域,AI的介入空间非常有限。我曾参与过一个跨国ERP项目,当本地团队与总部在交付标准上出现分歧时,最终是靠多次线下工作坊才达成共识——这种需要共情能力和政治智慧的场景,AI目前完全无法替代人类项目经理。
2.2 人机协作的新模式
智能工具正在改变项目经理的工作方式:
- 机械性工作自动化:Jira等工具已能自动生成燃尽图,ClickUp可以智能分配任务
- 决策支持增强:Power BI结合机器学习能预测项目健康度
- 沟通效率提升:Notion AI可自动生成会议纪要
但工具永远只是工具。就像自动驾驶汽车仍需人类监督一样,项目管理的最终决策权仍在人类手中。去年我们使用AI工具预测项目风险时,系统将某个关键开发者的请假标记为高风险,但实际上我们早就安排了AB角机制——这说明再智能的系统也需要人类经验来校准。
3. 认证考试的现实价值分析
3.1 职场竞争力维度
在招聘市场,认证的作用呈现两极分化:
- 初级岗位:PMP认证能使简历通过率提升40%(据PMI官方数据)
- 资深岗位:企业更关注实际项目经验,但认证仍是薪酬谈判的筹码
特别值得注意的是国企和事业单位。在参与政府信息化项目投标时,具备高级软考证书的技术人员数量往往是硬性指标。去年某智慧城市项目招标文件中就明确要求:"项目团队需至少包含3名信息系统项目管理师(高级)"。
3.2 知识体系维度
系统化学习的价值常被低估。自学项目管理容易陷入"工具迷恋症",而认证体系的课程设计强制建立了完整知识框架。我辅导过的许多转型项目经理都有类似体会:考完PMP后才真正理解变更管理流程的价值,之前都是在凭直觉处理需求变更。
4. 不同人群的决策建议
4.1 技术转型管理者
对于从开发岗转向管理的技术骨干,我强烈建议先考软考高级(信息系统项目管理师)。这个认证既有技术深度又涵盖管理知识,特别适合需要同时管理技术方案和团队的项目经理。备考过程能系统掌握立项论证、配置管理等关键技术管理要点。
4.2 传统行业转型者
计划从建筑、制造等行业转向IT项目管理的人群,PMP是更好的选择。它的通用性框架能快速建立跨行业认知,且国际认可度更高。我的一个学员从土木工程转型做互联网产品管理,就是靠PMP搭建起了沟通桥梁。
4.3 应届毕业生
对于缺乏实战经验的毕业生,不建议立即报考高级认证。可以先从软考中级(系统集成项目管理工程师)入手,同步积累实践经验。记住:证书是能力的佐证而非替代,过早考取高级认证反而可能造成"纸面专家"的印象。
5. 备考策略的与时俱进
5.1 智能化备考工具
现代备考方式已发生革命性变化:
- 模拟考试:使用ExamTopics等平台的智能题库
- 概念理解:通过ChatGPT解析PMBOK中的复杂概念
- 记忆训练:Anki的自适应记忆卡片系统
但要注意工具使用的陷阱。去年有位考生过度依赖AI解题,结果在真实考试中遇到情景题就束手无策——因为AI无法模拟真实项目中的权衡取舍。
5.2 经验积累的新途径
没有项目经验怎么办?可以考虑:
- 参与开源项目(GitHub上寻找需要项目管理的repo)
- 用Notion重建过往课程设计的管理流程
- 在模拟平台如ProjectManagementSimulation.com积累决策经验
我特别推荐"逆向项目管理"练习:找一份完整的项目文档,反向推导其中的管理决策逻辑。这种方法能快速建立理论与实践的连接。
6. 认证后的持续成长
拿到证书只是起点。保持竞争力的关键包括:
- 每季度分析3个真实项目案例(可从PMI案例库获取)
- 掌握至少一个AI项目管理工具(如Fore# 1. 概述
本文分享 Dubbo 的线程池策略。在 《精尽 Dubbo 源码分析 —— 线程池》 一文中,我们已经看到了多种线程池和线程队列,那么 Dubbo 是如何使用它们的呢?
在 Dubbo 中,每个服务提供者被抽象成一个 Invoker 暴露服务。当服务消费者调用服务时,Dubbo 会根据不同的协议,转换成对应的 Invoker ,再调用服务提供者的逻辑。在这调用的过程中,Dubbo 根据不同的配置,会使用不同的线程池策略,处理调用。例如:
- 在 Dubbo 协议中,默认配置下,使用
FixedThreadPool。 - 在 Dubbo 协议中,可以配置
dispatcher="message",使用ThreadlessExecutor+ 共享线程池。 - 在 Rest 协议中,使用
ThreadlessExecutor+ 共享线程池。
下面,我们来看下具体的代码实现。
2. Dispatcher
com.alibaba.dubbo.common.threadpool.support.Dispatcher ,线程池调度器接口。代码如下:
Java复制@SPI(AllDispatcher.NAME)
public interface Dispatcher {
/**
* dispatch the message to threadpool.
*
* 调度消息到线程池
*
* @param handler 处理器
* @param url url
* @return ChannelHandler
*/
@Adaptive({Constants.DISPATCHER_KEY, "dispather", "channel.handler"})
// The last two parameters are reserved for compatibility with the old configuration
ChannelHandler dispatch(ChannelHandler handler, URL url);
}
@SPI(AllDispatcher.NAME)注解,Dubbo SPI 拓展点,默认为"all"。@Adaptive({Constants.DISPATCHER_KEY, "dispather", "channel.handler"})注解,基于 Dubbo SPI Adaptive 机制,加载对应的线程池调度器实现,使用URL.dispatcher属性。#dispatch(handler, url)方法,调度消息到线程池。其中,handler参数,可以理解为需要被线程池调度的实体。通过创建不同的 ChannelHandler 实现类,从而封装不同线程池调度策略的逻辑。
Dispatcher 内置五种线程池调度器实现,如下图所示:

2.1 AllDispatcher
com.alibaba.dubbo.common.threadpool.support.all.AllDispatcher ,实现 Dispatcher 接口,所有消息都派发到线程池,包括请求,响应,连接事件,断开事件等。代码如下:
Java复制public class AllDispatcher implements Dispatcher {
public static final String NAME = "all";
@Override
public ChannelHandler dispatch(ChannelHandler handler, URL url) {
return new AllChannelHandler(handler, url);
}
}
- 对应
AllChannelHandler处理器。
2.2 DirectDispatcher
com.alibaba.dubbo.common.threadpool.support.direct.DirectDispatcher ,实现 Dispatcher 接口,所有消息都不派发到线程池,全部在 IO 线程上直接执行。代码如下:
Java复制public class DirectDispatcher implements Dispatcher {
public static final String NAME = "direct";
@Override
public ChannelHandler dispatch(ChannelHandler handler, URL url) {
return handler;
}
}
- 直接返回
handler,所以是不派发到线程池。
2.3 MessageOnlyDispatcher
com.alibaba.dubbo.common.threadpool.support.message.MessageOnlyDispatcher ,实现 Dispatcher 接口,只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在 IO 线程上执行。代码如下:
Java复制public class MessageOnlyDispatcher implements Dispatcher {
public static final String NAME = "message";
@Override
public ChannelHandler dispatch(ChannelHandler handler, URL url) {
return new MessageOnlyChannelHandler(handler, url);
}
}
- 对应
MessageOnlyChannelHandler处理器。
2.4 ExecutionDispatcher
com.alibaba.dubbo.common.threadpool.support.execution.ExecutionDispatcher ,实现 Dispatcher 接口,只有请求消息派发到线程池,不含响应。响应和其它连接断开事件,心跳等消息,直接在 IO 线程上执行。代码如下:
Java复制public class ExecutionDispatcher implements Dispatcher {
public static final String NAME = "execution";
@Override
public ChannelHandler dispatch(ChannelHandler handler, URL url) {
return new ExecutionChannelHandler(handler, url);
}
}
- 对应
ExecutionChannelHandler处理器。
2.5 ConnectionOrderedDispatcher
com.alibaba.dubbo.common.threadpool.support.connection.ConnectionOrderedDispatcher ,实现 Dispatcher 接口,在 IO 线程上,将连接断开事件放入队列,有序逐个执行,其它消息派发到线程池。代码如下:
Java复制public class ConnectionOrderedDispatcher implements Dispatcher {
public static final String NAME = "connection";
@Override
public ChannelHandler dispatch(ChannelHandler handler, URL url) {
return new ConnectionOrderedChannelHandler(handler, url);
}
}
- 对应
ConnectionOrderedChannelHandler处理器。
3. ChannelHandler
在 Dispatcher 实现类的代码中,我们可以看到创建了对应的 ChannelHandler 实现类。那么,ChannelHandler 是什么呢?
com.alibaba.dubbo.remoting.ChannelHandler ,通道处理器接口。代码如下:
Java复制public interface ChannelHandler {
/**
* on channel connected.
*
* 连接完成
*
* @param channel channel.
*/
void connected(Channel channel) throws RemotingException;
/**
* on channel disconnected.
*
* 连接断开
*
* @param channel channel.
*/
void disconnected(Channel channel) throws RemotingException;
/**
* on message sent.
*
* 发送消息
*
* @param channel channel.
* @param message message.
*/
void sent(Channel channel, Object message) throws RemotingException;
/**
* on message received.
*
* 接收消息
*
* @param channel channel.
* @param message message.
*/
void received(Channel channel, Object message) throws RemotingException;
/**
* on exception caught.
*
* 发生异常
*
* @param channel channel.
* @param exception exception.
*/
void caught(Channel channel, Throwable exception) throws RemotingException;
}
- 从方法定义上,我们可以看到,ChannelHandler 处理通道( Channel )的各个事件。
3.1 WrappedChannelHandler
com.alibaba.dubbo.remoting.transport.dispatcher.WrappedChannelHandler ,实现 ChannelHandler 接口,包装的 ChannelHandler 实现类。代码如下:
Java复制public class WrappedChannelHandler implements ChannelHandler {
protected static final Logger logger = LoggerFactory.getLogger(WrappedChannelHandler.class);
protected final ChannelHandler handler;
protected final URL url;
/**
* 线程池
*/
protected final ExecutorService executor;
public WrappedChannelHandler(ChannelHandler handler, URL url) {
this.handler = handler;
this.url = url;
// 创建线程池
executor = (ExecutorService) ExtensionLoader.getExtensionLoader(ThreadPool.class).getAdaptiveExtension().getExecutor(url);
// 添加线程池到 DataStore 中
String componentKey = Constants.EXECUTOR_SERVICE_COMPONENT_KEY;
if (Constants.CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(Constants.SIDE_KEY))) {
componentKey = Constants.CONSUMER_SIDE;
}
DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
dataStore.put(componentKey, Integer.toString(url.getPort()), executor);
}
@Override
public void connected(Channel channel) throws RemotingException {
handler.connected(channel);
}
@Override
public void disconnected(Channel channel) throws RemotingException {
handler.disconnected(channel);
}
@Override
public void sent(Channel channel, Object message) throws RemotingException {
handler.sent(channel, message);
}
@Override
public void received(Channel channel, Object message) throws RemotingException {
handler.received(channel, message);
}
@Override
public void caught(Channel channel, Throwable exception) throws RemotingException {
handler.caught(channel, exception);
}
public ExecutorService getExecutor() {
return executor;
}
}
-
handler属性,被包装的通道处理器。 -
url属性,URL 对象,包含线程池的配置。 -
executor属性,线程池。在构造方法中,调用ExtensionLoader#getExecutor(url)方法,基于 Dubbo SPI Adaptive 机制,获得线程池实现对象。代码如下:Java复制public class ThreadPool$Adaptive implements com.alibaba.dubbo.common.threadpool.ThreadPool { public java.util.concurrent.Executor getExecutor(com.alibaba.dubbo.common.URL arg0) { if (arg0 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg0; String extName = url.getParameter("threadpool", "fixed"); if (extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.common.threadpool.ThreadPool) name from url(" + url.toString() + ") use keys([threadpool])"); com.alibaba.dubbo.common.threadpool.ThreadPool extension = (com.alibaba.dubbo.common.threadpool.ThreadPool) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.threadpool.ThreadPool.class).getExtension(extName); return extension.getExecutor(arg0); } }- 默认使用
"fixed"线程池类型。 - 在 《精尽 Dubbo 源码分析 —— 线程池》 一文中,我们已经看到四种线程池的实现。
- 默认使用
-
构造方法的最后部分,将线程池对象,添加到
dataStore中。因为,线程池是 全局共享 的,需要统一存储,避免重复创建。com.alibaba.dubbo.common.store.DataStore,数据存储接口。代码如下:Java复制@SPI("simple") public interface DataStore { /** * return a snapshot value of componentName */ Map<String, Object> get(String componentName); /** * retrieve value by componentName and key */ Object get(String componentName, String key); /** * store a key-value pair by componentName */ void put(String componentName, String key, Object value); /** * delete a key-value pair by componentName and key */ void remove(String componentName, String key); }- 通过
componentKey和port作为组合键。因为不同的协议使用不同的端口,所以通过port可以区分不同的协议服务器,例如dubbo和rest。
- 通过
3.1.1 关闭线程池
在 WrappedChannelHandler 中,实现了 java.io.Closeable 接口,在关闭时,会关闭线程池。代码如下:
Java复制@Override
public void close() throws IOException {
try {
if (executor != null) {
executor.shutdown();
}
} catch (Throwable t) {
logger.warn("fail to destroy thread pool of server: " + t.getMessage(), t);
}
}
- 在
AbstractServer#close()方法中,会调用该方法,关闭线程池。
3.2 ChannelHandlerDispatcher
com.alibaba.dubbo.remoting.transport.ChannelHandlerDispatcher ,实现 ChannelHandler 接口,通道处理器调度器实现类。代码如下:
Java复制public class ChannelHandlerDispatcher implements ChannelHandler {
private final Collection<ChannelHandler> channelHandlers;
public ChannelHandlerDispatcher() {
this(new HashSet<ChannelHandler>());
}
public ChannelHandlerDispatcher(Collection<ChannelHandler> channelHandlers) {
this.channelHandlers = channelHandlers;
}
public Collection<ChannelHandler> getChannelHandlers() {
return channelHandlers;
}
public ChannelHandlerDispatcher addChannelHandler(ChannelHandler handler) {
this.channelHandlers.add(handler);
return this;
}
public ChannelHandlerDispatcher removeChannelHandler(ChannelHandler handler) {
this.channelHandlers.remove(handler);
return this;
}
@Override
public void connected(Channel channel) throws RemotingException {
for (ChannelHandler listener : channelHandlers) {
try {
listener.connected(channel);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
}
}
@Override
public void disconnected(Channel channel) throws RemotingException {
for (ChannelHandler listener : channelHandlers) {
try {
listener.disconnected(channel);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
}
}
@Override
public void sent(Channel channel, Object message) throws RemotingException {
for (ChannelHandler listener : channelHandlers) {
try {
listener.sent(channel, message);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
}
}
@Override
public void received(Channel channel, Object message) throws RemotingException {
for (ChannelHandler listener : channelHandlers) {
try {
listener.received(channel, message);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
}
}
@Override
public void caught(Channel channel, Throwable exception) throws RemotingException {
for (ChannelHandler listener : channelHandlers) {
try {
listener.caught(channel, exception);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
}
}
}
- 通过
channelHandlers属性,聚合多个 ChannelHandler 实现类。在其接口方法实现中,循环调用channelHandlers,实现分发。
3.3 ExecutionChannelHandler
com.alibaba.dubbo.remoting.transport.dispatcher.execution.ExecutionChannelHandler ,实现 WrappedChannelHandler 抽象类,只有请求消息派发到线程池,不含响应。响应和其它连接断开事件,心跳等消息,直接在 IO 线程上执行。
3.3.1 构造方法
Java复制public class ExecutionChannelHandler extends WrappedChannelHandler {
public ExecutionChannelHandler(ChannelHandler handler, URL url) {
super(handler, url);
}
}
3.3.2 received
Java复制@Override
public void received(Channel channel, Object message) throws RemotingException {
// 获得线程池
ExecutorService executor = getExecutorService();
// 将收到的消息派发到线程池中处理
try {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.RECEIVED, message));
} catch (Throwable t) {
//TODO A temporary solution to the problem that the exception information can not be sent to the opposite end after the thread pool is full. Need a refactoring
//fix The thread pool is full, refuses to call, does not return, and causes the consumer to wait for time out
if (message instanceof Request && t instanceof RejectedExecutionException) {
Request request = (Request) message;
if (request.isTwoWay()) {
String msg = "Server side(" + url.getIp() + "," + url.getPort() + ") threadpool is exhausted ,detail msg:" + t.getMessage();
Response response = new Response(request.getId(), request.getVersion());
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
response.setErrorMessage(msg);
channel.send(response);
return;
}
}
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}
}
- 在 IO 线程中,接收消息。
- 提交到线程池,处理消息。其中,我们可以看到:
- 提交的任务是 ChannelEventRunnable ,可以理解为一个任务。
- 在 ChannelEventRunnable 中,会调用
handler的方法,处理消息。例如:DubboProtocol#requestHandler中。
- 当提交到线程池被拒绝时,根据消息是否是双向的,返回响应给调用方。例如,在 Dubbo 协议中,
Request#isTwoWay() = true时,需要返回响应。
3.4 MessageOnlyChannelHandler
com.alibaba.dubbo.remoting.transport.dispatcher.message.MessageOnlyChannelHandler ,实现 WrappedChannelHandler 抽象类,只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在 IO 线程上执行。
3.4.1 构造方法
Java复制public class MessageOnlyChannelHandler extends WrappedChannelHandler {
public MessageOnlyChannelHandler(ChannelHandler handler, URL url) {
super(handler, url);
}
}
3.4.2 received
Java复制@Override
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService executor = getExecutorService();
try {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.RECEIVED, message));
} catch (Throwable t) {
//TODO 临时解决线程池满后异常信息无法发送到对端的问题。待重构
//fix 线程池满了拒绝调用不返回,导致消费者一直等待超时
if (message instanceof Request && t instanceof RejectedExecutionException) {
Request request = (Request) message;
if (request.isTwoWay()) {
String msg = "Server side(" + url.getIp() + "," + url.getPort() + ") threadpool is exhausted ,detail msg:" + t.getMessage();
Response response = new Response(request.getId(), request.getVersion());
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
response.setErrorMessage(msg);
channel.send(response);
return;
}
}
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}
}
- 和
ExecutionChannelHandler#received(channel, message)方法,基本一致。
3.5 AllChannelHandler
com.alibaba.dubbo.remoting.transport.dispatcher.all.AllChannelHandler ,实现 WrappedChannelHandler 抽象类,所有消息都派发到线程池,包括请求,响应,连接事件,断开事件等。
3.5.1 构造方法
Java复制public class AllChannelHandler extends WrappedChannelHandler {
public AllChannelHandler(ChannelHandler handler, URL url) {
super(handler, url);
}
}
3.5.2 connected
Java复制@Override
public void connected(Channel channel) throws RemotingException {
ExecutorService executor = getExecutorService(); // 获得线程池
try {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.CONNECTED));
} catch (Throwable t) {
throw new ExecutionException("connect event", channel, getClass() + " error when process connected event .", t);
}
}
- 将连接事件提交到线程池中处理。
3.5.3 disconnected
Java复制@Override
public void disconnected(Channel channel) throws RemotingException {
ExecutorService executor = getExecutorService(); // 获得线程池
try {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.DISCONNECTED));
} catch (Throwable t) {
throw new ExecutionException("disconnect event", channel, getClass() + " error when process disconnected event .", t);
}
}
- 将断开事件提交到线程池中处理。
3.5.4 received
Java复制@Override
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService executor = getExecutorService(); // 获得线程池
try {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.RECEIVED, message));
} catch (Throwable t) {
//TODO 临时解决线程池满后异常信息无法发送到对端的问题。待重构
//fix 线程池满了拒绝调用不返回,导致消费者一直等待超时
if (message instanceof Request && t instanceof RejectedExecutionException) {
Request request = (Request) message;
if (request.isTwoWay()) {
String msg = "Server side(" + url.getIp() + "," + url.getPort() + ") threadpool is exhausted ,detail msg:" + t.getMessage();
Response response = new Response(request.getId(), request.getVersion());
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
response.setErrorMessage(msg);
channel.send(response);
return;
}
}
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}
}
- 将接收消息提交到线程池中处理。
3.5.5 caught
Java复制@Override
public void caught(Channel channel, Throwable exception) throws RemotingException {
ExecutorService executor = getExecutorService(); // 获得线程池
try {
executor.execute(new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.CAUGHT, exception));
} catch (Throwable t) {
throw new ExecutionException("caught event", channel, getClass() + " error when process caught event .", t);
}
}
- 将异常事件提交到线程池中处理。
3.6 ConnectionOrderedChannelHandler
com.alibaba.dubbo.remoting.transport.dispatcher.connection.ConnectionOrderedChannelHandler ,实现 WrappedChannelHandler 抽象类,在 IO 线程上,将连接断开事件放入队列,有序逐个执行,其它消息派发到线程池。
3.6.1 构造方法
Java复制public class ConnectionOrderedChannelHandler extends WrappedChannelHandler {
protected final ThreadPoolExecutor connectionExecutor;
private final int queuewarninglimit;
public ConnectionOrderedChannelHandler(ChannelHandler handler, URL url) {
super(handler, url);
// 创建连接和断开事件的线程池
String threadName = url.getParameter(Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME);
connectionExecutor = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(url.getPositiveParameter(Constants.CONNECT_QUEUE_CAPACITY, Integer.MAX_VALUE)), // 队列大小
new NamedThreadFactory(threadName, true), // 线程池的名字为 `threadName` ,daemon=true
new AbortPolicyWithReport(threadName, url) // 当任务添加到线程池中被拒绝时,会抛出 RejectedExecutionException
); // FIXME 没有地方释放 connectionExecutor!
// 队列剩余大小报警阀值
queuewarninglimit = url.getParameter(Constants.CONNECT_QUEUE_WARNING_SIZE, Constants.DEFAULT_CONNECT_QUEUE_WARNING_SIZE);
}
}
connectionExecutor属性,连接和断开事件的线程池。不同于executor,它是单线程,并且队列大小无限制( 默认Integer.MAX_VALUE)。queuewarninglimit属性,队列剩余大小报警阀值。在#connected(channel)和#disconnected(channel)方法中,会判断队列的剩余大小,超过告警阀值时,会打印告警日志。
3.6.2 connected
Java复制@Override
public void connected(Channel channel) throws RemotingException {
try {
// 检查线程池队列剩余大小
checkQueueLength();
// 将连接事件提交到线程池中处理
connectionExecutor.execute(new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.CONNECTED));
} catch (Throwable t) {
throw new ExecutionException("connect event", channel, getClass() + " error when process connected event .", t);
}
}
-
调用
#checkQueueLength()方法,检查线程池队列剩余大小。代码如下:Java复制private void checkQueueLength() { if (connectionExecutor.getQueue().size() > queuewarninglimit) { logger.warn(new IllegalThreadStateException("connectionordered channel handler `queue size: " + connectionExecutor.getQueue().size() + " exceed the warning limit number :" + queuewarninglimit)); } }- 超过告警阀值时,会打印告警日志。
-
将连接事件提交到线程池中处理。
3.6.3 disconnected
Java复制@Override
public void disconnected(Channel channel) throws RemotingException {
try {
// 检查线程池队列剩余大小
checkQueueLength();
// 将断开事件提交到线程池中处理
connectionExecutor.execute(new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.DISCONNECTED));
} catch (Throwable t) {
throw new ExecutionException("disconnected event", channel, getClass() + " error when process disconnected event .", t);
}
}
- 和
#connected(channel)方法,基本一致。
3.6.4 received
Java复制@Override
public void received(Channel channel, Object message) throws RemotingException {
// 获得普通线程池
ExecutorService executor = getExecutorService();
try {
// 将接收消息提交到线程池中处理
executor.execute(new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.RECEIVED, message));
} catch (Throwable t) {
//TODO 临时解决线程池满后异常信息无法发送到对端的问题。待重构
//fix 线程池满了拒绝调用不返回,导致消费者一直等待超时
if (message instanceof Request && t instanceof RejectedExecutionException) {
Request request = (Request) message;
if (request.isTwoWay()) {
String msg = "Server side(" + url.getIp() + "," + url.getPort() + ") threadpool is exhausted ,detail msg:" + t.getMessage();
Response response = new Response(request.getId(), request.getVersion());
response.setStatus(Response.SERVER_THREA[DPO](https://taotoken.net?utm_source=general)OL_EXHAUSTED_ERROR);
response.setErrorMessage(msg);
channel.send(response);
return;
}
}
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}
}
- 和
ExecutionChannelHandler#received(channel, message)方法,基本一致。
3.6.5 caught
Java复制@Override
public void caught(Channel channel, Throwable exception) throws RemotingException {
// 获得普通线程池
ExecutorService executor = getExecutorService();
try {
// 将异常事件提交到线程池中处理
executor.execute(new ChannelEventRunnable(channel, handler, ChannelEventRunnable.ChannelState.CAUGHT, exception));
} catch (Throwable t) {
throw new ExecutionException("caught event", channel, getClass() + " error when process caught event .", t);
}
}
- 和
ExecutionChannelHandler#caught(channel, exception)方法,基本一致。
4. ChannelEventRunnable
com.alibaba.dubbo.remoting.transport.ChannelEventRunnable ,实现 Runnable 接口,通道事件任务。代码如下:
Java复制public class ChannelEventRunnable implements Runnable {
/**
* 通道
*/
private final Channel channel;
/**
* 通道处理器
*/
private final ChannelHandler handler;
/**
* 通道状态
*/
private final ChannelState state;
/**
* 异常
*/
private final Throwable exception;
/**
* 消息
*/
private final Object message;
public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state) {
this(channel, handler, state, null);
}
public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state, Object message) {
this(channel, handler, state, message, null);
}
public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state, Throwable t) {
this(channel, handler, state, null, t);
}
public ChannelEventRunnable(Channel channel, ChannelHandler handler, ChannelState state, Object message, Throwable exception) {
this.channel = channel;
this.handler = handler;
this.state = state;
this.message = message;
this.exception = exception;
}
@Override
public void run() {
// 检查通道状态
switch (state) {
case CONNECTED:
try {
handler.connected(channel);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
}
break;
case DISCONNECTED:
try {
handler.disconnected(channel);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
}
break;
case SENT:
try {
handler.sent(channel, message);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
}
break;
case RECEIVED:
try {
handler.received(channel, message);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
}
break;
case CAUGHT:
try {
handler.caught(channel, exception);
} catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
}
