并发读写缓存实现机制(一):为什么ConcurrentHashMap可以这么快?
大家都知道ConcurrentHashMap的并发读写速度很快,但为什么它会这么快?这主要归功于其内部数据结构和独特的hash运算以及分离锁的机制。做游戏性能很重要,为了提高数据的读写速度,方法之一就是采用缓存机制。因此缓存的性能直接影响游戏的承载量和运行流畅度,作为核心基础设施,缓存必须具备以下方面的功能:
1.ConcurrentHashMap的数据结构

|
1
2 3 4 5 6 |
static final class HashEntry<K, V> {
final K key; final int hash; volatile AbsReference value; final HashEntry<K, V> next; } |
|
1
2 3 4 5 6 7 |
static final class Segment extends ReentrantLock implements Serializable {
transient volatile int count; transient int modCount; transient int threshold; transient volatile AtomicReferenceArray<HashEntry> table; final float loadFactor; } |
2.Hash运算的妙用
位运算定位数据在某数组中下标
3.ConcurrentHashMap中数据的定位
|
1
2 3 4 5 6 7 8 9 10 |
private static int hash(int h) {
// Spread bits to regularize both segment and index locations, // using variant of single-word Wang/Jenkins hash. h += (h << ) ^ 0xffffcd7d; h ^= (h >>> ); h += (h << ); h ^= (h >>> ); h += (h << ) + (h << ); ); } |
|
1
2 3 4 |
final Segment<K, V> segmentFor(int hash) {
// 这里的segmentMask就是数组长度-1 return segments[(hash >>> segmentShift) & segmentMask]; } |
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
AbsReference get(String key, int hash, CacheLoader<String, AbsReference> loader, boolean isLoad) {
final StopWatch watch = new Slf4JStopWatch(); try { ) { // 先看看数量是否大于0 HashEntry e = getEntry(key, hash); if (e != null) { // 这里只是一次无锁情况的快速尝试查询,如果未查询到,会在有锁情况下再查一次 AbsReference value = getLiveValue(key, hash, now()); watch.lap("cache.getLiveValue()"); if (value != null) { recordAccess(e); return value; } } } if (isLoad) { // 对象为null或者对象已过期,则从在锁的情况下再查一次,还没有则从DB中加载数据 AbsReference ref = lockedGetOrLoad(key, hash, loader); watch.lap("cache.lockedGetOrLoad()"); return ref; } } finally { postReadCleanup(); watch.stop("cache.get()"); } return null; } |
|
1
2 3 4 5 6 7 8 |
HashEntry getEntry(String key, int hash) {
// 首先拿到链头HashEntry,然后依次查找整个entry链 for (HashEntry e = getFirst(hash); e != null; e = e.next) { if (e.hash == hash && key.equals(e.key)) { return e; } } return null; } |
|
1
2 3 4 |
HashEntry<K, V> getFirst(int hash) {
AtomicReferenceArray<HashEntry> tab = table; return tab.get(hash & (tab.length() - 1)); } |
总结
并发读写缓存实现机制(一):为什么ConcurrentHashMap可以这么快?的更多相关文章
- 探索 ConcurrentHashMap 高并发性的实现机制--转
ConcurrentHashMap 是 Java concurrent 包的重要成员.本文将结合 Java 内存模型,来分析 ConcurrentHashMap 的 JDK 源代码.通过本文,读者将了 ...
- 【转】探索 ConcurrentHashMap 高并发性的实现机制
原文链接:https://www.ibm.com/developerworks/cn/java/java-lo-concurrenthashmap/ <探索 ConcurrentHashMap ...
- Qunar机票技术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了>99.7%。再往后,每提高0.1%,优化难度成指数级增长了。哪怕是千分之一,也直接影响用户体验,影响每天上万张机票的销售额。 在高并发场景下,提供了保证线程安全的对象、方法。比如经典的ConcurrentHashMap,它比起HashMap,有更小粒度的锁,并发读写性能更好。线程安全的StringBuilder取代S
Qunar机票技术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了>99.7%.再往后,每提高0.1%,优化难度成指数级增长了.哪怕是千分之一,也直接影响用户体验,影响每天上万张机 ...
- Redis 的缓存淘汰机制(Eviction)
本文从源码层面分析了 redis 的缓存淘汰机制,并在文章末尾描述使用 Java 实现的思路,以供参考. 相关配置 为了适配用作缓存的场景,redis 支持缓存淘汰(eviction)并提供相应的了配 ...
- php中并发读写文件冲突的解决方案
在这里提供4种高并发读写文件的方案,各有优点,可以根据自己的情况解决php并发读写文件冲突的问题. 对于日IP不高或者说并发数不是很大的应用,一般不用考虑这些!用一般的文件操作方法完全没有问题.但如果 ...
- php中并发读写文件冲突的解决方案(文件锁应用示例)
PHP(外文名: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言.语法吸收了C语言.Java和Perl的特点,入门门槛较低,易于学习,使用广泛,主要适 ...
- 使用Spring提供的缓存抽象机制整合EHCache为项目提供二级缓存
Spring自身并没有实现缓存解决方案,但是对缓存管理功能提供了声明式的支持,能够与多种流行的缓存实现进行集成. Spring Cache是作用在方法上的(不能理解为只注解在方法上),其核心思想是 ...
- 艺多不压身 -- 常用缓存Cache机制的实现
常用缓存Cache机制的实现 缓存,就是将程序或系统经常要调用的对象存在内存中,以便其使用时可以快速调用,不必再去创建新的重复的实例. 这样做可以减少系统开销,提高系统效率. 缓存主要可分为二大类: ...
- 【Java 并发】Executor框架机制与线程池配置使用
[Java 并发]Executor框架机制与线程池配置使用 一,Executor框架Executor框架便是Java 5中引入的,其内部使用了线程池机制,在java.util.cocurrent 包下 ...
随机推荐
- SDK Manager 中 没有 Support Library怎么弄?
SDK Manager 中 没有 Support Library怎么弄?求大神帮忙 百度上面说的基本都试了,依旧没有弄出来 点击"Packages" > "Show ...
- Back-propagation, an introduction
About Contact Subscribe Back-propagation, an introduction Sanjeev Arora and Tengyu Ma • Dec 20, ...
- Web前端MVC框架
MVC: 模型层(model).视图层(view).控制层(controller) Model:即数据模型,用来包装和应用程序的业务逻辑相关的数据或者对数据进行处理,模型可以直接访问数据. View: ...
- oracle 用户与表空间关系
oracle用户与表空间关系用户=商家表=商品表空间=仓库1. 1个商家能有很多商品,1个商品只能属于一个商家2. 1个商品可以放到仓库A,也可以放到仓库B,但不能同时放入A和B3. 仓库不属于任何商 ...
- solr6.0.0 + tomcat8 配置问题
中间件需求: apache-tomcat-8.0.32.tar.gz jdk-8u74-linux-x64.rpm solr-6.0.0.zip 0.安装java JDK rpm -ivh jdk-8 ...
- Three.js开发指南---使用three.js里的各种光源(第三章)
本章的主要内容 1 three.js有哪些可用的光源 2 什么时候用什么光源. 3 如何调整配置各种光源 4 如何创建镜头炫光 一 光源 光源大概有7种, 其中基础光源有4种 环境光(AmbientL ...
- 判断Activity是否正在退出 isFinishing()
boolean android.app.Activity.isFinishing() Added in API level 1 Check to see whether this ...
- 给破坏性的Rake任务加把锁 | Rails
抄自这里 直接贴代码 # lib/tasks/skip_prod.rake desc 'Raises exception if used in production' task skip_prod: ...
- 【java】之joda-time的使用
Joda-Time Home:http://joda-time.sourceforge.net/ JavaDoc:http://joda-time.sourceforge.net/apidocs/in ...
- <<Differential Geometry of Curves and Surfaces>>笔记
<Differential Geometry of Curves and Surfaces> by Manfredo P. do Carmo real line Rinterval I== ...