并发读写缓存实现机制(一):为什么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 包下 ...
随机推荐
- DB2 claim与drain
DB2使用claim & drain来控制SQL与utility对数据库对象的访问. claim说明有对象正在访问或是将要访问该对象,而drain则是在对象上面加一个drain lock,等所 ...
- inotify +rsync进行实时同步
1.安装rpm -ivh http://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpmyum -y install ino ...
- Apache Tomcat 7 安装与配置
下载 首先需要下载tomcat7的安装文件,地址如下: http://mirror.bit.edu.cn/apache/tomcat/tomcat-7/v7.0.69/bin/apache-tomca ...
- winform中dataGridView单元格根据值设置新值,彻底解决绑定后数据类型转换的困难
// winform中dataGridView单元格在数据绑定后,数据类型更改困难,只能迂回实现.有时候需要将数字变换为不同的文字描述,就会出现int32到string类型转换的异常,借助CellFo ...
- Android模拟器连接本李服务器localhost
Android模拟(simulator)把它自己作为了localhost,也就是说,代码中使用 localhost或者127.0.0.1来访问,都是访问模拟器自己! 如果你想在模拟器simulator ...
- 解决错误: Failed to load class "org.slf4j.impl.StaticLoggerBinder"
当报这个错时,就很难看到我们自己输出的日志,系统运行情况后台无法得到输出.解决方案是加入以下依赖: <dependency> <groupId>org.slf4j</gr ...
- Managing a node remotely by using the netapp SP
Managing a node remotely by using the Service Processor The Service Processor (SP) is a remote manag ...
- 【java】之joda-time的使用
Joda-Time Home:http://joda-time.sourceforge.net/ JavaDoc:http://joda-time.sourceforge.net/apidocs/in ...
- mysql:权限分配
grant all privileges on *.* to name@localhost identified by '1'; flush privileges;
- oracle中找出某个字段中有非数字型的记录
工作中遇到一个大表记录中有非法非数字字符,不想用正则语法去做, 用一条SQL语句查出来的方法如下: select * from table where translate(col,'*01234567 ...