You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现Spring WebSocket全局同步计数器,多客户端共享计时状态

全局同步WebSocket计时器实现方案

要实现多客户端同步显示同一个计时器状态,核心是把计时状态抽离为全局共享变量,用独立线程驱动计时逻辑,并统一管理所有在线客户端会话,具体实现如下:

核心思路

  • 用静态变量存储全局计时状态(时、分、秒)和运行标记,保证所有客户端共享同一状态
  • 用线程安全的集合维护所有在线WebSocket会话,避免并发操作问题
  • 启动独立后台线程处理计时逻辑,避免每个客户端请求重复创建线程
  • 统一向所有在线客户端推送计时消息,确保同步

完整代码实现

package primer;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

@Component
public class SocketTextHandler extends TextWebSocketHandler {
    // 全局共享的计时变量,volatile保证多线程可见性
    private static volatile int hours = 0;
    private static volatile int minutes = 0;
    private static volatile int seconds = 0;
    // 标记计时器是否正在运行
    private static volatile boolean timerRunning = false;
    // 线程安全的会话集合,存储所有在线客户端
    private static final Set<WebSocketSession> sessions = new CopyOnWriteArraySet<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 客户端连接成功后,加入会话集合
        sessions.add(session);
        // 新客户端连接后,立即发送当前计时状态
        sendCurrentTimeToSession(session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, org.springframework.web.socket.CloseStatus status) throws Exception {
        // 客户端断开连接后,从会话集合移除
        sessions.remove(session);
    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws InterruptedException, IOException {
        String clientMessage = message.getPayload();
        
        if (clientMessage.startsWith("start")) {
            // 只有当计时器未运行时,才启动计时线程
            synchronized (SocketTextHandler.class) {
                if (!timerRunning) {
                    timerRunning = true;
                    startTimerThread();
                }
            }
        } else if (clientMessage.startsWith("stop")) {
            // 停止计时器并重置状态
            synchronized (SocketTextHandler.class) {
                timerRunning = false;
                hours = 0;
                minutes = 0;
                seconds = 0;
                // 向所有客户端发送重置后的状态
                broadcastTime();
            }
        }
    }

    // 启动计时线程,每秒更新时间并推送
    private void startTimerThread() {
        new Thread(() -> {
            while (timerRunning) {
                try {
                    Thread.sleep(1000);
                    // 更新计时状态
                    synchronized (SocketTextHandler.class) {
                        seconds++;
                        if (seconds >= 60) {
                            seconds = 0;
                            minutes++;
                            if (minutes >= 60) {
                                minutes = 0;
                                hours++;
                                if (hours >= 60) {
                                    hours = 0;
                                }
                            }
                        }
                    }
                    // 向所有客户端广播当前时间
                    broadcastTime();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }).start();
    }

    // 向所有在线客户端推送当前时间
    private void broadcastTime() {
        String timeStr = String.format("%02d:%02d:%02d", hours, minutes, seconds);
        TextMessage timeMessage = new TextMessage(timeStr);
        // 遍历所有会话发送消息,跳过已关闭的会话
        for (WebSocketSession session : sessions) {
            if (session.isOpen()) {
                try {
                    session.sendMessage(timeMessage);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 向单个会话发送当前时间
    private void sendCurrentTimeToSession(WebSocketSession session) throws IOException {
        String timeStr = String.format("%02d:%02d:%02d", hours, minutes, seconds);
        session.sendMessage(new TextMessage(timeStr));
    }
}

关键细节说明

  • volatile关键字:修饰计时变量和运行标记,确保多线程下的状态可见性,避免线程缓存旧值
  • CopyOnWriteArraySet:线程安全的会话集合,适合频繁遍历、较少修改的场景,避免并发修改异常
  • 同步块:在修改全局状态或启动/停止计时器时加锁,避免多线程竞争导致的状态混乱
  • 独立计时线程:只在第一次收到start指令时启动,后续客户端发送start不会重复创建线程,保证全局唯一计时逻辑
  • 会话管理:在连接建立/断开时维护会话集合,新客户端连接立即同步当前计时状态,确保一致性

内容的提问来源于stack exchange,提问作者Artemiy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 12:20:53