加锁的位置 (eq:map<key,map<>> 双集合 怎么 只加锁 在用到的对象位置,而不是把整个集合锁住)
比如上边的map里套map 定义变量为data,例如组队副本 npc 为1 下有众多房间 即Map<1,<roomId,room>> ,处于多线程下,一个线程在 npc为1的下边建一个房间,房间id为1即Map<1,<1,room>> ,这时候另外一个线程同时也要在 npc为1下建一个房间id为2的房间 即 Map<1,<2,room>> ,那我代码里肯定是 先
<roomId,room> rooms = data.get(1); 假如 rooms为null,则 rooms = new Map<roomId,room>(); 然后 put到 data里,即 data.put(1,rooms);但是问题就在这,多线程下, 怎么能保证 多个线程 只new 一个 rooms,而不是每个线程 都 各自new 一个rooms,这就是要加锁了,但是要想保证只new 一个rooms出来,那必须 要在整个data上加锁,这问题就来了,我明明就只想保证new 一个rooms出来,结果我把整个data锁起来,假如这边npc 的id 不仅仅有1,还有其他2,3,4,5,6,7... 这时候怎么办,如果所整个data,那其他npc 对应的rooms 也将被锁住,性能消耗出现问题,那怎么办呢,好办,先把 data 定义成 ConcurrentHashMap,即
ConcurrentHashMap data = null; 然后利用 ConcurrentHashMap 中的 putIfAbsent()方法,ConcurrentHashMap为线程安全的集合,putIfAbsent()也为线程安全的原子级 操作,所以
可以 直接 data.putIfAbsent(1,new <roomId,room>); putIfAbsent()含义即 key对应的值 如果不存在的话就new一个出来然后放进去(第一次putIfAbsent()直接返回null,
同普通map 的put方法一样,如果map中没有key对应的值,第一次put时返回null,以后每次由于有值了返回才是 key对应的那个存在的值,这里putIfAbsent()第一次如果没有就new 值然后放进去 后
返回同理也是null,以后get才会拿到key对应的值),如果存在就返回旧的值(不会new,直接用旧的返回)。分析一下,假如2个线程都同时来npc为1的rooms,2个拿到的rooms假如都是null,都需要
new 新的rooms,第一个线程先putIfAbsent()时,由于 putIfAbsent() 方法是原子级的线程安全,使得第二个线程调用 putIfAbsent()时处于阻塞状态,直到第一个线程调用putIfAbsent()
结束后释放锁后第二个线程才能够调用 putIfAbsent(),由于第一个已经new一个新的而且放入到data里了,第二个线程调用putIfAbsent()时从data里能拿到值了所以就不会再new新的,而是直接就用
第一个线程 new的那个值,这样就保证了多线程建的同步安全。 补:还有一种恶心的同步加锁,比如 组队副本中 有Map<npcId,Map<roomId,room>> 这个结构定义变量为data, 这个 data 有加入房间(将玩家加入到room中)、有退出房间(room 中删除玩家,
room中没人时这个room还要从data里remove)、有 快速匹配房间 操作(将room从data中remove掉),这三种操作都会修改room,有的是给room中加人,有的是给room中减人和删除room,有的是
直接就删除room,这时候肯定就要加锁了,比如一个线程在我给room加人时,另外一个线程刚好把这个room给从data中remove 掉了,那就算第一个我的线程 给room中加人成功了又有什么用,你加成功了
结果这个房间都从data中remove掉了,也就是你是在第一个线程加到room里,结果第二个线程把room 从data中remove掉,那第一个线程加的那个人就进入二次元空间了,因为那个room在data中的引用被
remove了,room整个是被遗弃了,room整个被删除进入回收状态,room整个进入二次元了,那room里的人肯定更是进入二次元空间了,加入这时候在加人时 有 人每天加入房间次数的限制,那第一个线程
处理的那个人就会被坑掉一次,这样数据就错乱了,所以就要加锁,那这个锁又怎么加呢? Map<roomId,room> rooms = data.get(npcId); 难道对这个rooms进行加锁? 那假如我在加入一个房间,
结果把整个npc下对应的rooms都锁住了,其他玩家的一些不是 加人都房间的操作(比如 退出房间等操作)也是不能做了,那不加整个rooms的锁的话又怎么能不会造成数据错乱呢? 解决方法有一个思路,
就是操作哪个共享的对象就对哪个对象加锁,这里加人是操作单个room,那就对整个room加锁才是最合法的做法,那又怎么保证同步数据安全呢?解决方法是在 room中加一个状态,即我加锁在这单个room上,
然后在同步块中 进行这个单个room 中那个状态的判断,由于其他线程操作时也会锁住这个单个room,所以这个状态的修改肯定是只能由一个线程同时修改,所以就不会数据错乱问题了。
加锁的位置 (eq:map<key,map<>> 双集合 怎么 只加锁 在用到的对象位置,而不是把整个集合锁住)的更多相关文章
- map泛型 map不指定泛型 与 Map<Object,Object>的区别
map泛型 map不指定泛型 与 Map<Object,Object>的区别 private void viewDetail(){ Map map1 = new HashMap(); Ma ...
- InputSplit—>RecordReder—>map(key,value,context)的过程解析
上图首先描述了在TaskTracker端Task(MapTask.ReduceTask)的执行过程,MapTask(org.apache.hadoop.mapred)首先被TaskRunner调用,然 ...
- Java之Map接口(双列集合)
Map集合概述 现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射.Java提供了专门的集合类用来存放这种对象关系的对 ...
- Map<Key,Value>基于Value值排序
Map<Key,Value> 排序默认是按照KEY值的升序来进行. 针对按照Value来进行排序有两种方法: 第一种 使用TreeMap 代码如下 public class test{ ...
- js解析json,js转换json成map,获取map的key,value
json串格式 { "10.10.11.1": { "target_1": "34.2", "target_3": &q ...
- C++ map<key , value> key值为指针
STL中map的key能否用char *呢?当然可以! 在程序中需要用到一个map,本来是这样写的, map<string, int> mapStr; 为了追求效率,把string改成了c ...
- map访问key不存在的情况下,用find。比[]直接访问的意思不一样,map[key]不返null
key不存在的话则创建一个pair并调用默认构造函数 map<CGuid, CLibItem>::iterator iterItem = m_world->m_library_sce ...
- Sass Maps的函数-map-remove($map,$key)、keywords($args)
map-remove($map,$key) map-remove($map,$key) 函数是用来删除当前 $map 中的某一个 $key,从而得到一个新的 map.其返回的值还是一个 map.他并不 ...
- Sass函数:Sass Maps的函数-map-has-key($map,$key)
map-has-key($map,$key) 函数将返回一个布尔值.当 $map 中有这个 $key,则函数返回 true,否则返回 false. 前面的示例,当 $key 不在 $map 中时,使用 ...
随机推荐
- [组件封装]微信小程序-底部弹框
描述 模仿ios浏览器底部弹框效果. 遮罩层淡入淡出,弹框高度根据内容自适应. 效果 源码 popup-bottom.wxml <!-- popup-bottom.wxml --> < ...
- 什么是Hibernate
Hibernate是一个基于JDBC的主流持久性框架,是一个优秀的ORM(object relation mapping)(对象关系映射)实现 ORM就是通过java对象映射到数据库表中,通过操作ja ...
- elasticsearch实战(1)-单机快速部署
1. 场景描述 elasticsearch只用过,没有部署或者维护过,从头完整走一遍,记录下,原创实战,有需要的朋友参考下. 2 . 解决方案 特别说下,以前win7下安装的3台虚拟机,没有联网,因为 ...
- 3.Scikit-Learn实现完整的机器学习项目
1 完整的机器学习项目 完成项目的步骤: (1) 项目概述 (2) 获取数据 (3) 发现并可视化数据,发现规律. (4) 为机器学习算法准备数据. (5) ...
- promise的优势
通过不同的方式读取在 files 文件夹下的三个文件来引出 promise 在处理异步时与回调函数相比的优势,files 文件夹有三个文件 a.json,b.json,c.json. // a.jso ...
- 【总结】办公&编程&学习你可能需要这些小利器!
偶然想到自己从最开始的编程小白,什么都不懂,看啥啥新鲜的时期,到现在颇有"蓦然回首,那人却在灯火阑珊处"的感觉,遂想整理一下这一路学习我个人发现的在办公.编程或者学新知识等方面针对 ...
- 理解卷积神经网络中的输入与输出形状(Keras实现)
即使我们从理论上理解了卷积神经网络,在实际进行将数据拟合到网络时,很多人仍然对其网络的输入和输出形状(shape)感到困惑.本文章将帮助你理解卷积神经网络的输入和输出形状. 让我们看看一个例子.CNN ...
- 性能计数器在.NET Core中的新玩法
传统的.NET Framework提供的System.Diagnostics.PerformanceCounter类型可以帮助我们收集Windows操作系统下物理机或者进程的性能指标,基于Perfor ...
- 线程状态以及sleep yield wait join方法
前言 在日常的开发过程中,我们通过会使用Thread.sleep模拟一个耗时的任务执行过程. 在深入理解这四个方法之前,首先对线程的状态进行理解阐述. 线程概念 线程是操作系统执行任务的基本单位,处理 ...
- JS事件之onmouseover 、onmouseout 与onmouseenter 、onmouseleave区别
疫情过后回武汉的第一天打卡,今天偶然遇到一个问题onmouseover .onmouseout 与onmouseenter .onmouseleave这些事件的区别,也看了一些博客,感觉不是很清楚,所 ...