比如上边的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<>> 双集合 怎么 只加锁 在用到的对象位置,而不是把整个集合锁住)的更多相关文章

  1. map泛型 map不指定泛型 与 Map<Object,Object>的区别

    map泛型 map不指定泛型 与 Map<Object,Object>的区别 private void viewDetail(){ Map map1 = new HashMap(); Ma ...

  2. InputSplit—>RecordReder—>map(key,value,context)的过程解析

    上图首先描述了在TaskTracker端Task(MapTask.ReduceTask)的执行过程,MapTask(org.apache.hadoop.mapred)首先被TaskRunner调用,然 ...

  3. Java之Map接口(双列集合)

    Map集合概述 现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射.Java提供了专门的集合类用来存放这种对象关系的对 ...

  4. Map<Key,Value>基于Value值排序

    Map<Key,Value> 排序默认是按照KEY值的升序来进行. 针对按照Value来进行排序有两种方法: 第一种 使用TreeMap  代码如下 public class test{ ...

  5. js解析json,js转换json成map,获取map的key,value

    json串格式 { "10.10.11.1": { "target_1": "34.2", "target_3": &q ...

  6. C++ map<key , value> key值为指针

    STL中map的key能否用char *呢?当然可以! 在程序中需要用到一个map,本来是这样写的, map<string, int> mapStr; 为了追求效率,把string改成了c ...

  7. map访问key不存在的情况下,用find。比[]直接访问的意思不一样,map[key]不返null

    key不存在的话则创建一个pair并调用默认构造函数 map<CGuid, CLibItem>::iterator iterItem = m_world->m_library_sce ...

  8. Sass Maps的函数-map-remove($map,$key)、keywords($args)

    map-remove($map,$key) map-remove($map,$key) 函数是用来删除当前 $map 中的某一个 $key,从而得到一个新的 map.其返回的值还是一个 map.他并不 ...

  9. Sass函数:Sass Maps的函数-map-has-key($map,$key)

    map-has-key($map,$key) 函数将返回一个布尔值.当 $map 中有这个 $key,则函数返回 true,否则返回 false. 前面的示例,当 $key 不在 $map 中时,使用 ...

随机推荐

  1. Nvue/Weex

    Nvue/Weex 使用Uniapp做了一个App,感觉性能不是很好,了解过Uniapp的Nvue,就想做一个纯Nvue项目,其实基本就是做一个Weex项目,不得不说坑是真的多,但是渲染性能真的是没得 ...

  2. hdu1429 胜利大逃亡(续)???天天逃亡???

    题目链接:http://icpc.njust.edu.cn/Problem/Hdu/1429/ 题目就是迷宫问题的变种,给出一张地图,上面分布着钥匙和门,一种要是只能开一种特定的门,给出起点和终点,问 ...

  3. JavaWeb----Cookie&Session

    ##  会话技术 1.会话:一次会话中包含多次请求和响应. *  第一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止. 2.功能:再一次会话的范围内的多次请求间,共享数据 3. ...

  4. Netty中ChannelHandler的生命周期

    在使用Netty进行网络编程的时候,通常需要在网络连接的不同阶段进行相应的操作,比如在连接建立时,客户端向服务端发起认证,在接收到数据时对数据内容进行解析等等.那么,连接的不同阶段在netty中如何表 ...

  5. 单调栈-Maximum Width Ramp

    2020-01-23 19:39:26 问题描述: 问题求解: public int maxWidthRamp(int[] A) { Stack<Integer> stack = new ...

  6. [AI开发]一个例子说明机器学习和深度学习的关系

    深度学习现在这么火热,大部分人都会有‘那么它与机器学习有什么关系?’这样的疑问,网上比较它们的文章也比较多,如果有机器学习相关经验,或者做过类似数据分析.挖掘之类的人看完那些文章可能很容易理解,无非就 ...

  7. 使用FME裁剪矢量shapefile文件

  8. Dubbo与Spring Cloud的比较

    区别: ----- 来源(背景): Dubbo,是阿里巴巴服务化治理的核心框架,并被广泛应用于阿里巴巴集团的各成员站点. Spring Cloud,从命名我们就可以知道,它是Spring Source ...

  9. MySQL的MVCC机制

    1.MVCC简介 1.1 MVCC是什么? MVCC,Multi-Version Concurrency Control,多版本并发控制.MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对 ...

  10. [noip模拟]心<并查集>

    背景描述: 不是一切深渊都是灭亡 不是一切灭亡都覆盖在弱者的头上 ——<这也是一切> 舒婷 有N个透明的盒子, 每个盒子里面有两个不同颜色的球, 总共有M种颜色. Alice和Bob又在玩 ...