前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何保证集合是线程安全的? ConcurrentHashMap如何实现高效地线程安全?

如何保证集合是线程安全的? ConcurrentHashMap如何实现高效地线程安全?

作者头像
葆宁
发布2019-04-18 15:33:58
1.5K0
发布2019-04-18 15:33:58
举报
文章被收录于专栏:FREE SOLOFREE SOLO

Java 提供了不同层面的线程安全支持。在传统集合框架内部,除了 Hashtable 等同步容器,还提供了所谓的同步包装器(Synchronized Wrapper),我们可以调用 Collections 工具类提供的包装方法,来获取一个同步的包装容器(如 Collections.synchronizedMap),

但是它们都是利用非常粗粒度的同步方式,在高并发情况下,性能比较低下。

更加普遍的选择是利用并发包提供的线程安全容器类, 它提供了:

各种并发容器,比如 ConcurrentHashMap、CopyOnWriteArrayList。 各种线程安全队列(Queue/Deque),如 ArrayBlockingQueue、SynchronousQueue。 各种有序容器的线程安全版本等。

具体保证线程安全的方式,包括有从简单的 synchronize 方式,到基于更加精细化的,比如基于分离锁实现的 ConcurrentHashMap 等并发实现等。具体选择要看开发的场景需求,总体来说,并发包内提供的容器通用场景,远优于早期的简单同步实现。

Hashtable 本身比较低效,因为它的实现基本就是将 put、get、size 等各种方法加 上“synchronized”。简单来说,这就导致了所有并发操作都要竞争同一把锁,一个线程在进 行同步操作时,其他线程只能等待,大大降低了并发操作的效率。

早期 ConcurrentHashMap,其实现是基于:

分离锁,也就是将内部进行分段(Segment),里面则是 HashEntry 的数组,和 HashMap 类似,哈希相同的条目也是以链表形式存放。

HashEntry 内部使用 volatile 的 value 字段来保证可见性,也利用了不可变对象的机制以改 进利用 Unsafe 提供的底层能力,比如 volatile access,去直接完成部分操作,以最优化性 能,毕竟 Unsafe 中的很多操作都是 JVM intrinsic 优化过的。

在这里插入图片描述
在这里插入图片描述

在构造的时候,Segment 的数量由所谓的 concurrentcyLevel 决定,默认是 16,也可以在相应构造函数直接指定。注意,Java 需要它是 2 的幂数值,如果输入是类似 15 这种非幂*值,会被自动调整到 16 之类 2 的幂数值。

在 Java 8 和之后的版本中,ConcurrentHashMap 发生了哪些变化呢?

总体结构上,,同样是大的桶(bucket)数组,然后内部也是一个个所谓的链表结构(bin),同步的粒度要更细致一些。其内部仍然有 Segment 定义,但仅仅是为了保证序列化时的兼容性而已,不再有任何结构上的用处。 因为不再使用 Segment,初始化操作大大简化,修改为 lazy-load 形式,这样可以有效避免 初始开销。 数据存储利用 volatile 来保证可见性。 使用 CAS 等操作,在特定场景进行无锁并发操作。 使用 Unsafe、LongAdder 之类底层手段,进行极端情况的优化。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年04月12日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档