Java NIO实现的简易分布式任务调度服务端采用非阻塞IO管理Worker/Client连接,基于JSON协议处理注册、心跳、任务分发与结果上报;通过Selector主循环处理网络事件,ScheduledExecutorService驱动定时调度,ConcurrentHashMap维护Worker状态,实现轻量级内存调度与故障剔除。

用 Java NIO 实现一个“简易的分布式任务调度服务端”,核心目标不是替代 Quartz 或 XXL-JOB,而是理解底层通信与调度模型:用 NIO 做轻量级、非阻塞的客户端连接管理 + 任务分发,配合简单协议和内存调度器。它适合学习、原型验证或极简边缘场景。
一、明确角色与协议设计(先想清楚再写代码)
分布式调度至少包含三类角色:服务端(Scheduler)、执行节点(Worker)、任务提交者(Client)。NIO 服务端主要承担:
- 接收 Worker 注册(带 IP、能力标签、心跳)
- 接收 Client 提交的任务(JSON/二进制,含 cron 表达式、执行命令、超时等)
- 按策略(如轮询、标签匹配)将任务推送给在线 Worker
- 接收 Worker 的执行结果与心跳,剔除离线节点
协议建议用轻量 JSON over TCP,例如注册报文:{"type":"REGISTER","id":"w-001","tags":["java","io-heavy"],"ip":"192.168.1.10","port":8081};任务下发:{"type":"SCHEDULE","taskId":"t-123","cmd":"curl -s http://api/status","cron":"0 * * * * ?","timeout":30000}。
二、基于 Selector 的多路复用服务端骨架
不依赖 Netty,纯 JDK NIO 构建主循环。关键点:
立即学习“Java免费学习笔记(深入)”;
- 一个 ServerSocketChannel 绑定端口,设置为非阻塞,注册
OP_ACCEPT - 所有 SocketChannel(Client/Worker 连接)也设为非阻塞,注册
OP_READ(可选OP_WRITE用于响应) - 用 ByteBuffer 缓存读写数据,每个连接维护独立 buffer(避免粘包,需简单解析边界,如换行或长度前缀)
- 用 ConcurrentHashMap<String, SocketChannel> 存 Worker ID → Channel 映射;用 CopyOnWriteArrayList<Task> 存待调度任务(仅作示意,生产需持久化)
示例 accept 处理片段:
if (key.isAcceptable()) {
SocketChannel ch = serverChannel.accept();
ch.configureBlocking(false);
ch.register(selector, SelectionKey.OP_READ, new ConnectionContext());
}
三、任务调度逻辑嵌入在业务线程中(非 Selector 线程)
Selector 线程只负责 IO,调度决策必须剥离。推荐做法:
- 用 ScheduledExecutorService 每秒触发一次调度检查(模拟 cron 解析+触发)
- 遍历内存中未完成任务,对满足触发条件(如 cron 到时、无依赖)的,查在线 Worker 列表,按策略选一个
- 将任务序列化后写入对应 Worker 的 SocketChannel(注意 OP_WRITE 可能未就绪,需注册并缓存待写 buffer)
- Worker 执行完 POST 回结果,服务端收到后更新任务状态,并从内存移除
注意:任务触发和网络发送是两个异步阶段,不能阻塞 Selector;失败重试、超时取消需单独线程或定时任务兜底。
四、Worker 心跳与故障剔除(保障分布式可靠性)
NIO 本身不提供心跳,需协议层实现:
- Worker 启动后每 10 秒发一次
{"type":"HEARTBEAT","id":"w-001"} - 服务端为每个 Worker 记录最后心跳时间(AtomicLong 或 ConcurrentHashMap + 时间戳)
- 另起一个守护线程,每 15 秒扫描 Worker 列表,剔除超过 25 秒无心跳的节点,并关闭其 SocketChannel
- 剔除时触发回调:将分配给它的进行中任务标记为“丢失”,后续可重调度(简易版 failover)
这比单纯靠 TCP 断连更及时——NIO 中 channel.close() 后,下次 select 会触发 OP_READ 或 OP_CONNECT 异常,但网络闪断可能延迟数分钟才感知。


















