动态更新全局数据
来源:互联网 发布:前端页面优化 编辑:程序博客网 时间:2024/06/06 05:49
想象这样一种场景,有一份全局数据在启动的时候加载,多线程并发访问这份全局数据,那么在运行过程中如何动态更新这份全局数据?
前面说到的问题,究根结底在于读写操作是并发的,不可避免的会出现冲突。例如有一张物品价格表,多个线程并发查询这张表获取物品价格,另外一个线程想更新物品价格。这种场景,我们可以抽象为单生产者-多消费者的问题。
通常的做法,就是直接重启程序一了百了,但是如果重启的代价比较大可能这种方法就不好用了。还有一种做法就是每次访问的时候加锁,可是加锁明显非常影响性能。有没有一种办法可以动态更新数据,又不能影响到性能?答案是有,我们以实际数据为例说明。
假设有一个全局物品表,用map存储。我们可以定义两个同样结构的物品表:itemsA_,itemsB_,还有一个标志表示当前用的是哪个物品表:flagA_。访问数据的时候,如果flagA_为true,那么访问的就是itemsA_,反之就是itemsB_。更新数据的时候,如果flagA_为true,更新的就是itemsB_,并且将flagA_置为false,反之同理。通过这种方式,读取和修改两种操作就不会冲突,因为他们操作的是两份不同的数据。
细心的同学会发现,代码中flagA_的类型是volatile bool。这个关键字volatile的用处在于,它告诉编译器不要对这个变量的相关代码进行优化,同时每次都要重新读取这个值,而不是去寄存器读旧的数据。如果不加volatile会有什么问题呢?假如现在flagA_是true,那么写线程会将数据更新到itemsB_,并且将flagA_置为false。这时候读线程去读数据,那么它认为flagA_是多少?答案是有可能还是true。为什么会这样,写线程不是将flagA_置为false了吗?原因是处理器为了提高效率,会将数据缓存到寄存器中,在读取数据的时候,可能只是从寄存器读旧的数据,而不是从内存中读最新的数据。所以加上volatile还是必要的,这样能保证线程每次读取的都是最新的flagA_。
当然同学会发现还有一个不同的地方,那就是在代码行63和68加了语句:MemoryBarrier()。可能有同学认为这个语句没什么用,因为从常理来说,更新items之后,再更新flag,那么读线程肯定会读到正确的数据,除非执行语句不按代码的顺序来。很不幸地恭喜你猜对了!虽然你看到了代码是这种顺序,但是实际上执行的顺序还真可能不是这样的。这里要说到的内容就是指令重排和内存屏障(MemoryBarrier)。我们知道,现代计算机,CPU的性能已经远远超过内存的性能,所以为了提高效率,CPU会将一些不会互相影响的指令同时执行。在这份代码中为了更新数据我们做了两个操作:itemsB_= items; flagA_ =false。那么这样写可能会出现的情况是,CPU判断两个语句中的指令互不干扰,因为CPU有多个处理单元,所以同时执行不冲突的指令。那么可能出现的结果是,flagA_已经变成false,但是可能itemsB_= items还没有执行完。在这个时候,读线程读取数据,因为flagA_ =false,所以获取的是itemsB_的数据。但是根据前面的描述,itemsB_还在赋值,所以问题就出现了,我们读取了一份还在赋值的数据。而MemoryBarrier()的作用就在于,让这个语句之后的指令在前面的语句执行完后才能执行。通过这个语句,就可以避免指令重排问题的出现。
- 动态更新全局数据
- Vue2 全局-Vue.set更新vue数据
- Listview动态更新数据
- 动态更新highcharts数据
- Mybatis动态更新数据
- JTable数据的动态更新
- Android: ListView动态更新数据
- DataTables ajax 动态更新数据
- ListView的动态更新数据
- 场景数据的动态更新
- flex图表数据动态更新效果示例
- DWR实时自动动态更新网页数据
- Java JTable 实现数据动态更新
- AchartEngine动态更新ContentProvider数据并绘图
- Android Fragment 数据动态更新的问题
- Android操作数据的动态更新ListView
- Android Fragment 数据动态更新的问题
- Android Fragment 数据动态更新的问题
- Python3 字典
- locate命令的使用
- request与response以及编码的介绍
- 球钟问题
- 黑苹果的问题说明
- 动态更新全局数据
- RecyclerView中嵌套RecyclerView或其他可滑动布局抢占焦点的问题
- HDU3974Assign the task(DFS序+线段树)
- qt 设置阴影 不显示黑色边框
- Mike and gcd problem
- Java开发中的23种设计模式详解
- log4j2入门(二) 使用详解
- 操作系统下载
- 基于微信的产品设计01:注册登录及账号体系设计