当前位置: 首页 > web >正文

并发设计模式实战系列(2):领导者/追随者模式

 

🌟 ​大家好,我是摘星!​ 🌟

今天为大家带来的是并发设计模式实战系列,第二章领导者/追随者(Leader/Followers)模式,废话不多说直接开始~

目录

领导者/追随者(Leader/Followers)

为什么需要领导者/追随者(Leader/Followers)模式?

一、核心原理深度拆解

1. 角色轮转机制

2. 关键技术实现

二、生活化类比:医院分诊系统

三、Java代码实现(生产级Demo)

1. 完整可运行代码

2. 关键机制说明

四、横向对比表格

1. 线程模型对比

2. 性能优化策略对比

五、高级实践技巧

1. 动态Leader选举优化

2. 负载均衡策略

3. 监控关键指标

六、总结与适用场景

1. 核心优势

2. 典型应用场景

3. 模式局限


领导者/追随者(Leader/Followers)

为什么需要领导者/追随者(Leader/Followers)模式?

在现代高并发系统中,我们面临一个关键挑战:
高并发监听 vs. 高效任务处理

  • 监听瓶颈:传统Reactor模式中,单个Selector线程可能成为性能瓶颈(如10万+连接时)
  • 线程竞争:多线程同时监听同一Selector会导致epoll_ctl锁竞争(Linux内核级锁)
  • 上下文切换:任务队列的生产者-消费者模型引入额外调度开销

领导者/追随者模式通过角色轮换机制解决这一矛盾:

  • Leader线程:独占监听权限,避免多线程竞争Selector
  • Follower线程:无监听开销,专注处理任务
  • 动态切换:处理事件后立即移交领导权,实现负载均衡

一、核心原理深度拆解

1. 角色轮转机制

              +-----------------+|  事件到达        |+--------+--------+|+-----------v-----------+ | Leader线程监听事件     |←----++-----------+-----------+     || 处理事件        |+-----------v-----------+     || 指定新Leader          |     |+-----------+-----------+     ||                 |+-----------v-----------+     || Follower晋升为Leader  |-----++-----------------------+
  • 三阶段工作流
    1. 监听事件:Leader线程独占监听资源(如Selector)
    2. 事件分派:检测到事件后指定新Leader
    3. 角色转换:原Leader转为Worker处理事件,新Leader继续监听

2. 关键技术实现

  • 线程状态管理:使用AtomicInteger记录角色状态(LEADER=0, PROCESSING=1, FOLLOWER=2)
  • 无锁化设计:通过CAS操作实现Leader选举
  • 事件分发器:维护ThreadPool保存所有工作线程

二、生活化类比:医院分诊系统

系统组件

现实类比

核心行为

Leader线程

导诊台护士

识别患者类型,分配接诊医生

Follower线程

诊室医生

专注处理当前患者

事件队列

候诊区座位

缓冲等待处理的患者

  • 工作流程
    1. 导诊护士(Leader)发现新患者
    2. 指定空闲医生(新Leader)接替导诊工作
    3. 原护士转为医生处理当前患者

三、Java代码实现(生产级Demo)

1. 完整可运行代码

import java.nio.channels.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;public class LeaderFollowersServer {private static final int MAX_THREADS = 8;private final AtomicInteger leaderStatus = new AtomicInteger(0); // 0=可用, 1=忙碌// 线程工作单元class Worker implements Runnable {private final Selector selector;private volatile boolean isLeader = false;public Worker(Selector selector) {this.selector = selector;}@Overridepublic void run() {while (!Thread.interrupted()) {try {// 尝试成为Leaderif (leaderStatus.compareAndSet(0, 1)) {isLeader = true;System.out.println(Thread.currentThread().getName() + " 成为Leader");// 监听事件(非阻塞模式)selector.selectNow();for (SelectionKey key : selector.selectedKeys()) {if (key.isAcceptable()) {handleAccept((ServerSocketChannel) key.channel());}}// 移交Leader身份leaderStatus.set(0);isLeader = false;} else {// 作为Follower处理事件TimeUnit.MILLISECONDS.sleep(100);}} catch (Exception e) {e.printStackTrace();}}}private void handleAccept(ServerSocketChannel server) {try {SocketChannel client = server.accept();System.out.println(Thread.currentThread().getName() + " 处理连接: " + client);// 模拟业务处理TimeUnit.MILLISECONDS.sleep(500);} catch (Exception e) {e.printStackTrace();}}}public void start() throws Exception {Selector selector = Selector.open();ServerSocketChannel ssc = ServerSocketChannel.open();ssc.bind(new java.net.InetSocketAddress(8080));ssc.configureBlocking(false);ssc.register(selector, SelectionKey.OP_ACCEPT);ExecutorService pool = Executors.newFixedThreadPool(MAX_THREADS);for (int i = 0; i < MAX_THREADS; i++) {pool.execute(new Worker(selector));}}public static void main(String[] args) throws Exception {new LeaderFollowersServer().start();}
}

2. 关键机制说明

// CAS实现无锁选举
if (leaderStatus.compareAndSet(0, 1)) { // 成功获取Leader身份
}// 优雅退出处理
selector.wakeup(); // 唤醒阻塞的select()
pool.shutdownNow(); // 关闭线程池

四、横向对比表格

1. 线程模型对比

特性

Leader/Followers

Half-Sync/Half-Async

Reactor

上下文切换

少(角色转换)

中等

多(事件传递)

资源消耗

低(固定线程数)

中等

吞吐量

高(无锁设计)

极高

适用场景

短连接服务

混合型任务

纯异步任务

编程复杂度

高(需处理状态转换)

中等

2. 性能优化策略对比

优化方向

Leader/Followers

传统线程池

CPU利用率

通过角色切换减少竞争

依赖队列管理

内存消耗

固定线程数控制

动态扩容可能OOM

延迟稳定性

更均匀的任务分配

存在长尾效应

扩展性

水平扩展需重新设计

容易增加线程数


五、高级实践技巧

1. 动态Leader选举优化

// 使用Phaser实现协调
Phaser phaser = new Phaser(1);
while (true) {phaser.arriveAndAwaitAdvance();// 选举新Leader...
}

2. 负载均衡策略

// 基于处理能力的Leader选择
if (worker.getLoad() < threshold) {promoteToLeader(worker);
}

3. 监控关键指标

// Leader切换频率监控
AtomicLong leaderChangeCount = new AtomicLong();// 线程负载统计
ConcurrentHashMap<Worker, Integer> workloadMap = new ConcurrentHashMap<>();

六、总结与适用场景

1. 核心优势

低竞争:单线程监听 + 动态Leader选举,减少锁争用
高吞吐:无队列中转,事件直接由工作线程处理
资源可控:固定线程数,避免OOM风险

2. 典型应用场景

  • 短连接服务:如HTTP API网关、游戏服务器
  • 低延迟系统:金融交易订单处理
  • 均匀负载场景:任务处理耗时差异小的业务

3. 模式局限

⚠️ 不适合长任务:Leader长时间占用会导致监听阻塞
⚠️ 实现复杂度高:需精细控制线程状态转换

http://www.xdnf.cn/news/164.html

相关文章:

  • 基于Django实现农业生产可视化系统
  • 使用Python设置Excel单元格边框
  • 快手本地生活2024年GMV同增200%,“新线城市+AI”将成增长引擎
  • 【嵌入式八股11】STM32
  • (8)VTK C++开发示例 --- 交互式3D部件
  • 【Reading Notes】(8.3)Favorite Articles from 2025 March
  • “星睿O6” AI PC开发套件评测 - 部署PVE搭建All in One NAS服务器
  • STM32单片机入门学习——第40节: [11-5] 硬件SPI读写W25Q64
  • ASP.NET 中 OAuth 2.0/OpenID Connect 深度集成指南
  • Silverlight发展历程(微软2021年已经停止支持Silverlight 5)
  • 【深度学习】【目标检测】【Ultralytics-YOLO系列】YOLOV3核心文件yolo.py解读
  • Redis(二) - Redis命令详解
  • GPU 在机器学习中的应用优势:从技术特性到云端赋能
  • 银行卡风险画像在社交行业网络安全的应用
  • 如何使用 DeepSeek 帮助自己的工作?
  • 进阶版:RESTful API 在不同编程语言中的实现与实践
  • MCP认证难题破解
  • 搜广推校招面经七十八
  • 爬虫学习——Scrapy
  • LangChain4j-第一篇 |几分钟完成deepseek 在线集成
  • 三大等待和三大切换
  • Leetcode 2158. 每天绘制新区域的数量【Plus题】
  • MySQL:Join连接的原理
  • 54常用控件_QLCDNumber的属性
  • 支持mingw g++14.2 的c++23 功能print的vscode tasks.json生成调试
  • 细节:如何制作高质量的VR全景图
  • 《软件设计师》复习笔记(11.6)——系统转换、系统维护、系统评价
  • 【dataframe显示不全问题】打开一个行列超多的excel转成df之后行列显示不全
  • 25MathorCup选题浅析(睡醒扫一眼题目版)
  • Spark on K8s 在 vivo 大数据平台的混部实战与优化