96SEO 2026-02-23 14:17 14
在多线程环境下操作可能会导致程序死循环》一文的朋友们一定知道其中有一个解决办法就是使用

第一种方法使用Hashtable线程安全类第二种方法使用Collections.synchronizedMap方法对方法进行加同步锁第三种方法使用并发包中的ConcurrentHashMap类
几乎所有的添加、删除、查询方法都加了synchronized同步锁
相当于给整个哈希表加了一把大锁多线程访问时候只要有一个线程访问或操作该对象那其他线程只能阻塞等待需要的锁被释放在竞争激烈的多线程场景中性能就会非常差所以
再来看看第二种方法使用Collections.synchronizedMap方法我们打开
做的方法做了一层包装里面使用对象锁来保证多线程场景下操作安全本质也是对
使用Collections.synchronizedMap方法在竞争激烈的多线程环境下性能依然也非常差所以不推荐使用
上面2种方法由于都是对方法进行全表锁所以在多线程环境下容易造成性能差的问题因为hashMap
链表的数据结构如果我们把数组进行分割多段对每一段分别设计一把同步锁这样在多线程访问不同段的数据时就不会存在锁竞争了这样是不是可以有效的提高性能
再来看看第三种方法使用并发包中的ConcurrentHashMap类
组成其中小数组继承自ReentrantLock可重入锁这个小数组名叫Segment
以及next都使用了volatile关键字修饰保证了多线程环境下数据获取时的可见性
这个静态内部类继承了ReentrantLock类ReentrantLock是一个可重入锁如果了解过多线程的朋友们对它一定不陌生。
ReentrantLock和synchronized都可以实现对线程进行加锁不同点是ReentrantLock可以指定锁是公平锁还是非公平锁操作上也更加灵活关于此类具体在以后的多线程篇幅中会单独介绍。
因为ConcurrentHashMap的大体存储结构和HashMap类似所以就不对每个方法进行单独分析介绍了关于HashMap的分析有兴趣的朋友可以参阅小编之前写的《深入分析
初始化方法有三个参数initialCapacity初始化容量为16、loadFactor负载因子为0.75、concurrentLevel并发等级为16如果不指定则会使用默认值。
在多线程环境下操作可能会导致程序死循环仔细想想你会发现造成这个问题无非是
第一步尝试获取对象锁如果获取到返回true否则执行scanAndLockForPut方法这个方法也是尝试获取对象锁第二步获取到锁之后类似
已存在如果已经存在通过标识符判断是否覆盖默认覆盖第四步如果不存在采用头插法插入到
我们再来看看上面提到的scanAndLockForPut这个方法源码如下
对象如果重试次数大于最大次数就调用lock()方法获取对象锁如果依然没有获取到当前线程就阻塞直到获取之后退出循环在这个过程中key
通过scanAndLockForPut()方法当前线程就可以在即使获取不到segment锁的情况下完成需要添加节点的实例化工作当获取锁后就可以直接将该节点插入链表即可。
这个方法还实现了类似于自旋锁的功能循环式的判断对象锁是否能够被成功获取直到获取到锁才会退出循环防止执行
方法就比较简单了因为不涉及增、删、改操作所以不存在并发故障问题源码如下
先获取对象锁计算key的hash值在HashEntry[]中的角标根据index角标获取HashEntry对象循环遍历HashEntry对象HashEntry为单向链表结构通过key和hash判断key是否存在如果存在就移除元素并将需要移除的元素节点的下一个向上移最后就是释放对象锁以便其他线程使用
引入了红黑二叉树设计当冲突的链表长度大于8时会将链表转化成红黑二叉树结构红黑二叉树又被称为平衡二叉树在查询效率方面又大大的提高了不少。
key、value是否为空如果为空就抛异常接着会判断容器数组是否为空如果为空就初始化数组进一步判断要插入的元素f在当前数组下标是否第一次插入如果是就通过
-1是否成立如果成立说明当前f是ForwardingNode节点表示有其它线程正在扩容则一起进行扩容操作其他的情况就是把新的Node节点按链表或红黑树的方式插入到合适的位置节点插入完成之后接着判断链表长度是否超过8如果超过8个就将链表转化为红黑树结构最后插入完成之后进行扩容判断
是一个对象属性使用了volatile关键字修饰保证并发的可见性默认为
操作时通过Unsafe.compareAndSwapInt()方法俗称CAS将
如果别的线程发现sizeCtl0意味着有另外的线程执行CAS操作成功当前线程通过执行Thread.yield()让出
-1成立说明当前f是ForwardingNode节点意味有其它线程正在扩容则一起进行扩容操作源码如下
nextTable进行数据校验第2步根据数组的length得到一个标识符号第3步进一步校验
第1步利用CAS将方法更新baseCount的值第2步检查是否需要扩容默认check
1需要检查第3步如果满足扩容条件判断当前是否正在扩容如果是正在扩容就一起扩容第4步如果不在扩容将sizeCtl更新为负数并进行扩容处理
的流程基本分析完了可以从中发现里面大量的使用了CAS方法CAS
表示比较与替换里面有3个参数分别是目标内存地址、旧值、新值每次判断的时候会将旧值与目标内存地址中的值进行比较如果相等就将新值更新到内存地址里如果不相等就继续循环直到操作成功为止
虽然使用的了CAS这种乐观锁方法但是里面的细节设计的很复杂阅读比较费神有兴趣的朋友们可以自己研究一下。
方法操作就比较简单了因为不涉及并发操作直接查询就可以了源码如下
第1步判断数组是否为空通过key定位到数组下标是否为空第2步判断node节点第一个元素是不是要找到如果是直接返回第3步如果是红黑树结构就从红黑树里面查询第4步如果是链表结构循环遍历判断
第1步循环遍历数组接着校验参数第2步判断是否有别的线程正在扩容如果是一起扩容第3步用
-1所以不会进行扩容操作利用CAS操作修改baseCount值
引入了红黑树特性当冲突链表长度大于8时会将链表转化成红黑二叉树结构。
Boot/Cloud、Dubbo、JVM、集合、多线程、JPA、MyBatis、MySQL
等技术知识。
需要的小伙伴可以点击如下链接获取资源地址技术资料笔记。
不会有人刷到这里还想白嫖吧点赞对我真的非常重要在线求赞。
加个关注我会非常感激
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback