Skip to content

CHashMap 使用文档

CHashMap 是 Zeze 框架提供的并发哈希Map实现,内部使用多个 LinkedMap 分片来提高并发性能。不同分片可以同时被不同事务访问,从而减少锁竞争。所有操作都在事务中执行,数据会自动持久化到配置的数据库。

Zeze.Collections.CHashMap<V extends Bean>
特性说明
高并发多分片设计,减少锁竞争
持久化数据自动同步到数据库
事务安全所有操作在事务中执行
快速查找O(1) 平均时间复杂度
哈希分片根据键的哈希值自动分配到分片

// CHashMap 依赖 LinkedMap.Module
Zeze.Application zeze = new Zeze.Application(config);
LinkedMap.Module linkedMapModule = new LinkedMap.Module(zeze);
// 打开一个名为 "playerCache" 的 CHashMap
// 使用默认配置:256个分片,每个分片节点大小30
CHashMap<PlayerData> playerCache = linkedMapModule.openConcurrent("playerCache", PlayerData.class);
// 指定分片数量和节点大小
CHashMap<PlayerData> playerCache = linkedMapModule.openConcurrent("playerCache", PlayerData.class, 128);
// 开启事务
zeze.newProcedure(() -> {
// 添加元素
PlayerData player = new PlayerData();
player.name = "Alice";
player.level = 10;
playerCache.put("player_001", player);
// 获取元素
PlayerData data = playerCache.get("player_001");
// 获取或创建
PlayerData data = playerCache.getOrAdd("player_002");
// 删除元素
PlayerData removed = playerCache.remove("player_001");
// 获取元素数量
long count = playerCache.size();
// 判断是否为空
boolean empty = playerCache.isEmpty();
return 0;
}, "example").call();

Module 类方法(通过 LinkedMap.Module)

Section titled “Module 类方法(通过 LinkedMap.Module)”
方法说明
openConcurrent(String name, Class<T> valueClass)打开 CHashMap,默认256分片,节点大小30
openConcurrent(String name, Class<T> valueClass, int nodeSize)打开 CHashMap,默认256分片,指定节点大小
方法返回值说明
get(String key)V根据 key 获取值,不存在返回 null
getOrAdd(String key)V获取或创建值
put(String key, V value)V添加键值对,返回旧值
remove(String key)V删除元素,返回被删除的值
size()long获取元素总数
isEmpty()boolean判断是否为空
getName()String获取 CHashMap 名称

// 定义玩家数据Bean
public class PlayerData extends Bean {
public String name;
public int level;
public long exp;
// ...
}
// 使用 CHashMap 缓存玩家数据
CHashMap<PlayerData> playerCache = linkedMapModule.openConcurrent("players", PlayerData.class);
// 更新玩家数据
zeze.newProcedure(() -> {
PlayerData player = playerCache.getOrAdd("player_12345");
player.name = "Bob";
player.level = 20;
player.exp = 15000;
return 0;
}, "update_player").call();
// 读取玩家数据
zeze.newProcedure(() -> {
PlayerData player = playerCache.get("player_12345");
if (player != null) {
System.out.println("Player: " + player.name + ", Level: " + player.level);
}
return 0;
}, "read_player").call();
// 定义会话Bean
public class Session extends Bean {
public long userId;
public long loginTime;
public String deviceInfo;
}
// 使用 CHashMap 管理会话
CHashMap<Session> sessions = linkedMapModule.openConcurrent("sessions", Session.class);
// 创建会话
zeze.newProcedure(() -> {
Session session = new Session();
session.userId = 1001;
session.loginTime = System.currentTimeMillis();
session.deviceInfo = "Android";
sessions.put("session_" + session.userId, session);
return 0;
}, "create_session").call();
// 删除会话(登出)
zeze.newProcedure(() -> {
sessions.remove("session_1001");
return 0;
}, "logout").call();
// 定义商品库存Bean
public class ProductStock extends Bean {
public int productId;
public int count;
public long updateTime;
}
// 使用 CHashMap 管理库存
CHashMap<ProductStock> stockMap = linkedMapModule.openConcurrent("product_stock", ProductStock.class);
// 扣减库存
zeze.newProcedure(() -> {
ProductStock stock = stockMap.get("product_001");
if (stock != null && stock.count >= 10) {
stock.count -= 10;
stock.updateTime = System.currentTimeMillis();
return 0; // 成功
}
return -1; // 库存不足
}, "deduct_stock").call();
// CHashMap 的分片设计允许多个线程同时访问不同分片
// 下面的操作可以并发执行(假设访问不同的 key)
// 线程1:操作 player_aaa
zeze.newProcedure(() -> {
playerCache.put("player_aaa", new PlayerData());
return 0;
}, "thread1").call();
// 线程2:操作 player_bbb(与 player_aaa 可能在不同分片)
zeze.newProcedure(() -> {
playerCache.put("player_bbb", new PlayerData());
return 0;
}, "thread2").call();

CHashMap
├── buckets[0] → LinkedMap (name@0)
├── buckets[1] → LinkedMap (name@1)
├── buckets[2] → LinkedMap (name@2)
│ ...
└── buckets[n-1] → LinkedMap (name@n-1)
// 计算 key 应该放入哪个分片
int index = Integer.remainderUnsigned(ByteBuffer.calc_hashnr(key), buckets.length);
传统单锁Map:
Transaction1 ──锁──> [ Map ] <──锁── Transaction2
(串行等待)
CHashMap分片:
Transaction1 ──> [Bucket 0]
Transaction2 ──> [Bucket 1] (并行执行)
Transaction3 ──> [Bucket 2]
  • 每个 CHashMap 维护一个 sizes[] 数组
  • 每个分片的大小缓存在对应位置
  • 事务提交后通过 Transaction.whileCommit 更新
  • size() 方法通过累加所有分片大小得到总数,避免锁住所有桶

特性CHashMapLinkedMap
并发性能高(多分片)一般(单分片)
元素顺序无序有序(插入顺序)
顺序操作不支持支持 moveAhead/moveTail
遍历不支持支持 walk
适用场景高并发缓存、会话管理需要顺序的场景、背包

特性CHashMapConcurrentHashMap
持久化自动持久化到数据库仅内存
事务支持事务不支持
值类型必须是 Bean任意对象
分布式支持多进程共享单进程
性能相对较低(事务开销)

场景建议分片数说明
低并发(<10事务/秒)32-64减少资源占用
中等并发(10-100事务/秒)128平衡性能和资源
高并发(>100事务/秒)256+最大化并发性能
场景建议节点大小说明
频繁增删10-20减少节点内元素移动
稳定数据30-50减少节点数量
大数据量50-100减少存储开销

  1. 事务要求:所有操作必须在 Procedure 中执行
  2. 无序性:CHashMap 不保证元素顺序,不提供遍历功能
  3. 名称限制:名称不能包含 @ 字符(保留用于分片命名)
  4. 值类型:值类型必须继承自 Bean
  5. 分片数量:分片数量在创建时确定,之后不可修改
  6. Size 精度size() 返回的是近似值(基于缓存),不是实时精确值

ZezeJava/ZezeJava/src/main/java/Zeze/Collections/CHashMap.java