从 synchronized 到 ConcurrentHashMap:一个小小的并发控制策略升级优化,证明我还是初级程序员
我们是SpringBoot+Mybatisplus项目。我的一个工具方法中,需要获取entity对象对应数据表的 更新时间 字段(update_time 或 updateTime)。
代码完成后,考虑到Mybatisplus调用及java反射机制的性能损耗,我使用Map来缓存数据关系。
其中,考虑到并发调用,我随即在方法上加了synchronized。
private static Map<Class, String> updateTimeColumnMap = new HashMap<>();
/**
* 获取updateTime字段
*/
private synchronized static <Entity> String getUpdateTimeColumn(Class<Entity> clz) {
String updateTimeColumn = updateTimeColumnMap.get(clz);
if (updateTimeColumn == null) {
TableInfo tableInfo = TableInfoHelper.getTableInfo(clz);
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
if (fieldList.stream().anyMatch(p -> p.getColumn().contentEquals("update_time"))) {
updateTimeColumn = "update_time";
}
if (fieldList.stream().anyMatch(p -> p.getColumn().contentEquals("updateTime"))) {
updateTimeColumn = "updateTime";
}
updateTimeColumnMap.put(clz, updateTimeColumn);
}
return updateTimeColumn;
}
下班后消停了,我又在琢磨并发调用的问题,因为我知道 synchronized 锁的粒度比较粗,会影响性能。
发给AI后,立即给了我答案。很简单,利用 ConcurrentHashMap 的原子方法 computeIfAbsent来保证线程安全,无需显式加锁。基于CAS和无锁编程,这是最直接和高效的改进方式。
当然,此前的项目中也有使用 ConcurrentHashMap,只恨书到用时方恨少。确切地说,是没深刻掌握。
private static Map<Class, String> updateTimeColumnMap = new ConcurrentHashMap<>();
private static <Entity> String getUpdateTimeColumn(Class<Entity> clz) {
return updateTimeColumnMap.computeIfAbsent(clz, key -> {
TableInfo tableInfo = TableInfoHelper.getTableInfo(clz);
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
String columnName = null;
if (fieldList.stream().anyMatch(p -> "update_time".equals(p.getColumn()))) {
columnName = "update_time";
} else if (fieldList.stream().anyMatch(p -> "updateTime".equals(p.getColumn()))) {
columnName = "updateTime";
}
// 如果未找到,这里会缓存null,可考虑缓存空字符串""或一个特定的标识
return columnName;
});
}
从一种较重的“互斥锁”模式,升级为一种更轻量的“无锁编程”模式,这一次并发控制策略的升级CASE,也许证明我还停留在初级编程阶段。
知识就是力量,但更重要的,是..
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/19576604
浙公网安备 33010602011771号