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

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

  image.gif 编辑

🌟 大家好,我是摘星! 🌟

今天为大家带来的是并发设计模式实战系列,第二章领导者/追随者(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  |-----+
           +-----------------------+

image.gif

  • 三阶段工作流
  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;
        }
        @Override
        public void run() {
            while (!Thread.interrupted()) {
                try {
                    // 尝试成为Leader
                    if (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();
    }
}

image.gif

2. 关键机制说明

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

image.gif

四、横向对比表格

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...
}

image.gif

2. 负载均衡策略

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

image.gif

3. 监控关键指标

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

image.gif

六、总结与适用场景

1. 核心优势

低竞争:单线程监听 + 动态Leader选举,减少锁争用

高吞吐:无队列中转,事件直接由工作线程处理

资源可控:固定线程数,避免OOM风险

2. 典型应用场景

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

3. 模式局限

⚠️ 不适合长任务:Leader长时间占用会导致监听阻塞

⚠️ 实现复杂度高:需精细控制线程状态转换

目录
相关文章
|
2月前
|
设计模式 监控 Java
并发设计模式实战系列(1):半同步/半异步模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第一章半同步/半异步(Half-Sync/Half-Async)模式,废话不多说直接开始~
60 0
|
2月前
|
设计模式 运维 监控
并发设计模式实战系列(4):线程池
需要建立持续的性能剖析(Profiling)和调优机制。通过以上十二个维度的系统化扩展,构建了一个从。设置合理队列容量/拒绝策略。动态扩容/优化任务处理速度。检查线程栈定位热点代码。调整最大用户进程数限制。CPU占用率100%
180 0
|
2月前
|
设计模式 算法 Java
设计模式觉醒系列(04)策略模式|简单工厂模式的升级版
本文介绍了简单工厂模式与策略模式的概念及其融合实践。简单工厂模式用于对象创建,通过隐藏实现细节简化代码;策略模式关注行为封装与切换,支持动态替换算法,增强灵活性。两者结合形成“策略工厂”,既简化对象创建又保持低耦合。文章通过支付案例演示了模式的应用,并强调实际开发中应根据需求选择合适的设计模式,避免生搬硬套。最后推荐了JVM调优、并发编程等技术专题,助力开发者提升技能。
|
2月前
|
设计模式 消息中间件 监控
并发设计模式实战系列(3):工作队列
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第三章,废话不多说直接开始~
45 0
|
2月前
|
设计模式 Java 数据库连接
【设计模式】【创建型模式】工厂方法模式(Factory Methods)
一、入门 什么是工厂方法模式? 工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定实例化哪个类。工厂方法模式使类的实例化延迟
89 16
|
2月前
|
设计模式 安全 Java
并发设计模式实战系列(12):不变模式(Immutable Object)
🌟 大家好,我是摘星!🌟今天为大家带来的是并发设计模式实战系列,第十二章,废话不多说直接开始~
54 0
|
7月前
|
设计模式 前端开发 搜索推荐
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
350 11
|
2月前
|
设计模式 Prometheus 监控
并发设计模式实战系列(20):扇出/扇入模式(Fan-Out/Fan-In)(完结篇)
🌟 大家好,我是摘星!🌟今天为大家带来的是并发设计模式实战系列,第二十章,废话不多说直接开始~
77 0
|
8月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
10月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。

热门文章

最新文章