一次聊天服的压力测试中,偶然发现某个用户竟然收不到别的用户广播的消息,跟踪日志,该用户已成功登录,难道用户加入该消息广播组失败了?然而日志显示用户也已经成功加入了该消息广播组。。。
经过仔细检查,最终锁定了以上代码, 有什么问题么?</
经过仔细检查,最终锁定了以上代码, 有什么问题么?</
//key为组名,value为该组所有在线用户 ConcurrentHashMap<String, CopyOnWriteArrayList > groupSessions
List groupList = groupSessions.get(groupName); //检查是否已经存在该组,如果不存在,创建该组list并加入该组 if (groupList == null) { groupList=new CopyOnWriteArrayList(); groupSessions.putIfAbsent(groupName,groupList); } //将用户session加入到该组 groupList.add(session);
单机测试或者用户很少的时候,这段代码应该没什么问题(只是应该哦)。但是如果并发的话,线程A和线程B几乎同时进入if (groupList == null) 这段代码,线程A先执行完,所以groupList加入groupSessions,线程B执行groupSessions.putIfAbsent(groupName,groupList)由于该组已经存在(线程A加入),所以线程B的groupList没有加入到groupSessions组,而该用户的session加入的groupList不存在groupSessions组。那么广播该组消息时自然就该用户收不到消息了。
修改如下:
一行只差啊。List groupList = groupSessions.get(groupName); //检查是否已经存在该组,如果不存在,创建该组list并加入该组 if (groupList == null) { groupList=new CopyOnWriteArrayList(); groupList=groupSessions.putIfAbsent(groupName,groupList); } //将用户session加入到该组 groupList.add(session);