【Spring】验证 @ServerEndpoint 的类成员变量线程安全

前言

最近有 websocket 的需求。探索 @ServerEndpoint 的类成员变量特点。
这里类比 @Controller 讨论 @ServerEndpoint 类成员变量是否线程安全。

猜想来源

网上的教程大多数都这么展示程序:

@Component
@ServerEndpoint(value = "/ws")
public class MyWsEndpoint {

    private final MyContext context = new MyContext();

    @OnOpen
    public void onOpen(Session session) {
        
    }
    // ... 省略
}    

但是,同样的写法,类比 @Controller ,必然会产生线程安全问题。

@Controller
public class MyController {
    private static final Logger logger = LoggerFactory.getLogger(MyController.class);

    private final MyContext context = new MyContext();

    @GetMapping("/normal")
    @ResponseBody
    public String normal() {
        
    }
}

需要一种快速验证的方式, @ServerEndpoint 的类成员变量则线程安全


验证方法

  • 最简单的用例,把读和写拆成两个步骤,如果读到了其他线程的值,则为不安全的情况
        // 每个请求独立自增
        int currentCount = ac.incrementAndGet();
        
        // 多线程写
        context.setCurrentCount(currentCount);
        // 多线程读
        if (context.getCurrentCount() != currentCount) {
            logger.error("线程不安全!!!");
        }
  • 浏览器触发请求,多线程 debug 打断点 制造并发场景
    在这里插入图片描述

@Controller 的情况

  • 线程不安全
    原因是 @Controller 的类默认是单例的
    在这里插入图片描述

@ServerEndpoint 的情况

贴一个前端测试代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ws client</title>
</head>
<body>

</body>

<script>
    let ws = new WebSocket("ws://localhost:8080/ws")
    ws.onopen = function () {
        ws.send("hello")
    }

    ws.onmessage = function (message) {
        console.log(message)
    }
</script>
</html>
  • 线程安全
    在这里插入图片描述

后记

  • 上文验证了 @ServerEndpoint 的类成员变量是线程安全的。
  • 但是存在矛盾:
    • 上面用例 @Component@ServerEndpoint 共同作用于一个类上
    • Spring 容器管理 @Component 默认是单例的

  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值