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

Spring WebSocket多线程发消息报错[TEXT_PARTIAL_WRITING]求解决方案

解决Spring WebSocket多线程并发写入的TEXT_PARTIAL_WRITING错误

兄弟,这个问题我太熟了!之前做Spring WebSocket项目的时候踩过一模一样的坑——多线程同时往同一个WebSocket会话写消息,就会触发这个TEXT_PARTIAL_WRITING的无效状态错误,而且总不能把整个发送方法加个大锁吧?那样不同会话的发送操作都得串行,性能直接拉胯。下面给你几个靠谱的解决方案,按需选就行:

方案1:为每个WebSocketSession单独绑定锁

核心思路是只锁当前要发送的会话,不同会话的发送操作互不影响,完全并行。我们可以用ConcurrentHashMap来维护会话和对应锁对象的映射:

import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.TextMessage;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

public class WebSocketMessageSender {
    // 用ConcurrentHashMap存储每个会话对应的锁,线程安全
    private final ConcurrentHashMap<WebSocketSession, Object> sessionLocks = new ConcurrentHashMap<>();

    public void sendMessage(WebSocketSession session, TextMessage message) throws IOException {
        // 为当前会话获取或创建锁对象
        Object lock = sessionLocks.computeIfAbsent(session, k -> new Object());
        
        synchronized (lock) {
            // 先判断会话是否还处于打开状态
            if (session.isOpen()) {
                session.sendMessage(message);
            }
            // 会话关闭后可以移除对应的锁,避免内存泄漏
            else {
                sessionLocks.remove(session);
            }
        }
    }
}

这个方案的好处是轻量、可控,完全由自己管理锁的生命周期,不会影响其他会话的并发发送。

方案2:使用Spring官方的ConcurrentWebSocketSessionDecorator

Spring WebSocket自带了一个专门解决并发发送问题的装饰器ConcurrentWebSocketSessionDecorator,它内部会把同一个会话的发送请求排队串行执行,同时允许不同会话并行发送,还支持设置超时时间和缓冲区大小,简直是为这个场景量身定做的:

import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator;
import java.io.IOException;

public void handleSession(WebSocketSession session) {
    // 包装原始会话:第一个参数是原始会话,第二个是发送超时时间(毫秒),第三个是缓冲区大小
    ConcurrentWebSocketSessionDecorator decoratedSession = 
        new ConcurrentWebSocketSessionDecorator(session, 1000, 1024 * 1024);
    
    // 之后所有发送操作都用这个装饰后的会话
    try {
        decoratedSession.sendMessage(new TextMessage("Hello from concurrent sender!"));
    } catch (IOException e) {
        // 处理异常
    }
}

这个方案是我最推荐的,因为是官方实现,稳定性和兼容性都有保障,代码也最简洁,不用自己手动管理锁。

方案3:如果用STOMP协议,直接用SimpMessagingTemplate

如果你的项目是基于STOMP协议的WebSocket服务,那根本不用自己处理并发问题——Spring提供的SimpMessagingTemplate本身就是线程安全的,内部已经帮你搞定了会话的并发写入:

import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.beans.factory.annotation.Autowired;

@Service
public class StompMessageSender {
    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    public void sendToUser(String username, String destination, Object payload) {
        // 给指定用户发送消息,完全不用关心并发问题
        messagingTemplate.convertAndSendToUser(username, destination, payload);
    }

    public void sendToTopic(String destination, Object payload) {
        // 给主题发送广播消息,同样线程安全
        messagingTemplate.convertAndSend(destination, payload);
    }
}

这个方案适合用STOMP的场景,直接借助框架能力,零额外代码解决问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:36:22