[英]Removing Values from ConcurrentHashMap Properly
我正在制作一个简单的客户端服务器程序,该程序允许用户连接,更改其名称以及进入聊天室。 服务器会定期向每个客户端发送心跳信号(如果它们未处于活动状态),如果每个客户端均未响应,则将其删除。
为了进一步加强服务器清理,我还将定期检查我的房间是否空着,在这种情况下,我从服务器上删除了房间,以防止不必要的数据积累。 但是,此删除会带来问题。 我正在使用ConcurrentHashMap,它将房间名称映射到保存玩家名称及其插座的ConcurrentHashMap。 然后,定期地,我遍历每个房间,检查其中是否包含任何玩家(尺寸大于0)。 如果没有,我将房间移开。
但是,当服务器决定清理房间时,当用户选择加入空房间的确切时间时,这会带来非常麻烦的情况。 由于ConcurrentHashMap处理所有幕后同步,因此我无法同步此特定情况,因此删除是100%线程安全的。 用户可能正好在移开房间的同时加入房间,这导致他陷入了困境。
我该如何解决这个问题?
我将外部地图保留为ConcurrentHashMap,但将内部地图替换为ChatRoom类。 单个房间中的预期活动率似乎无法证明如此强大的并发图是合理的。
ChatRoom类应该是线程安全的,并且应具有“已关闭”标志,用于指示房间是否已关闭。 close()方法应使用房间的锁来更改标志,并使任何后续操作非法。 实际上,close方法应该返回一个布尔值,指示房间是否已经关闭; 当且仅当房间为空时,才应将其关闭。
您的空闲房间检查器线程应调用room.close(),然后将其从外部映射中删除。
您可以将同步方法添加到Room中,例如boolean closeIfEmpty()
。 如果成功,则可以安全地从地图上移除房间(使用2参数remove方法)。 如果添加代码尝试添加到封闭的房间,则添加操作将失败,并且调用方将创建一个新房间并替换该封闭的房间。
您可以在Room ConcurrentHashMap实例上同步删除操作和“向房间添加用户”操作,还可以在房间上保持“ closed”标志。
就像是
void scanRoomAndRemove(Map room) {
synchronized (room) {
// scan room, remove from parent Map if empty
room.put("closed",new Object());
}
}
void addPlayerToRoom(Player player,Map room) {
synchronized(room) {
if ( !room.containsKey("closed")) {
// add player to room
} else {
// whine here
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.