加锁的位置 (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 中时,使用 ...
随机推荐
- oracle中plsql练习题----查询姓为“SMITH”的员工信息,并输出其员工号、姓名、工资、部门号。 – –如果该员工不存在,则插入一条新记录,员工号为2012,员工姓名为“Smith”,工资为7500元,入职日期为“2002年3月5日”,部门号为50。 – –如果存在多个名“Smith”的员工,则输出所有名为“Smith”的员工号、姓名、工资、入职日期、部门号L。
一.思路:首先判断这个查询的是emp表,需要接收值,声明一个rowtype类型接收数据即可,第二是,存在exception,需要处理,exception中有两种异常,分别处理即可,分别输出即可. 二. ...
- Linux常用命令 - top命令详解(重点)
21篇测试必备的Linux常用命令,每天敲一篇,每次敲三遍,每月一循环,全都可记住!! https://www.cnblogs.com/poloyy/category/1672457.html top ...
- Fiddler3 使用技巧
1.Fiddler抓不到包怎么解决 (1)先确定是HTTP包抓不到还是HTTPS包抓不到.如果只是HTTPS包抓不到,说明是证书的问题,需要重新安装证书. (2)检查浏览器的HTTP代理设置是否正确, ...
- Netty Hello World 入门源码分析
第一节简单提了什么是网络编程,Netty 做了什么,Netty 都有哪些功能组件.这一节就具体进入 Netty 的世界,我们从用 Netty 的功能实现基本的网络通信开始分析 各个组件的使用. 1. ...
- Vue + element从零打造一个H5页面可视化编辑器——pl-drag-template
pl-drag-template Github地址:https://github.com/livelyPeng/pl-drag-template 前言 想必你一定使用过易企秀或百度H5等微场景生成工具 ...
- Kubernetes中Pod健康检查
目录 1.何为健康检查 2.探针分类 2.1.LivenessProbe探针(存活性探测) 2.2.ReadinessProbe探针(就绪型探测) 3.探针实现方法 3.1.Container Exe ...
- html5 window.postMessage 传递数据的使用
window.postMessage(图片介绍): 发送方(图片介绍): 接收方(图片介绍): 个人测试一(iframe): 发送方,地址为:http://localhost:63342/HelloH ...
- Hadoop调度器
一.FIFO调度器(先进先出调度) 上图为FIFO调度器的执行过程示意图.FIFO Scheduler是最简单也是最容易理解的调度器,它缺点是不适用于共享集群.大的应用可能会占用所有集群资源,这就导致 ...
- 深度强化学习(DRL)专栏(一)
目录: 1. 引言 专栏知识结构 从AlphaGo看深度强化学习 2. 强化学习基础知识 强化学习问题 马尔科夫决策过程 最优价值函数和贝尔曼方程 3. 有模型的强化学习方法 价值迭代 策略迭代 4. ...
- 对oracle里面clob字段里面xml的增删改查学习
这段时间,我使用系统表里面有clob字段里面存放的xml信息,我们如何对xml进行增删改查操作呢,自己参考了很多也学到很多,给大家分享一下 首先我们先建测试表 CREATE TABLE EFGP_23 ...