并发读写缓存实现机制(一):为什么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 包下 ...
随机推荐
- bind绑定多个事件切换
eg: $(function(){ $("div").bind('mouseover mouseover',function(){ $(this.tog ...
- linux下jdk的安装(tar包)
1.查看jdk安装路径 [root@localhost ~]# whereis javajava: /usr/bin/java /etc/java /usr/lib/java /usr/share/j ...
- 基于CWMP(TR069)协议ACS服务器的搭建
Linux上安装openacs Openacs的安装分为四大步: 1.安装jdk 2.安装jboss 3.安装mysql 4.部署openacs JDK简介 Java DevelopmentKit(J ...
- mybatis 与 xml
mybatis的两大重要组件:配置和映射文件,都是可以通过xml配置的(新版本新增了注解的方式配置Mapper),下面来解析下mybatis是怎么做的 其中,关于配置文件解析的主要是在这个类XMLCo ...
- Hadoop学习笔记
今天开始要学习Hadoop!开始向"大数据"领域靠拢! 从头开始对于连何为Hadoop都不清楚的人,有好多东西要学,加油! 1.下载hadoop,官网地址:http://mirro ...
- 01 Linux档案与目录管理
1. 目录与路径 1.1绝对路径和相对路径 绝对路径:一定有根目录/写起,例如:/usr/share/doc 相对路径:不是由根目录/写起,例如:由/usr/sha ...
- linux中service *** start与直接运行/usr/bin/***的区别
在linux想要运行启动一个服务有两种方法: 1,运行/etc/init.d/目录下的shell脚本,还可以有快捷方式,service *** start/ stop/restart /status, ...
- coderforces 731c
题目大意:给出m组数据,每组数据包括两个数Li与Ri,分别表示左右袜子的索引(下标),表示这一天要穿的袜子:而我们要使得每天穿的这两只袜子的颜色相同,所以可以改变袜子的颜色,每次只能改变一只袜子的颜色 ...
- tinyPng Photoshop Plugin 安装的坑
一定要注意两点: 第一: 注册表注册路径要修改为自己安装ps cc时的注册表路径[HKEY_LOCAL_MACHINE\SOFTWARE\Adobe\Photoshop\70.0]第二: Applic ...
- OAF_开发系列25_实现OAF中Java类型并发程式开发oracle.apps.fnd.cp.request(概念)
20150719 Created By BaoXinjian