【counrrenthashmap】17、看看你了解多少?

本问题对应的项目链接:高频题回答模版训练

说明:counrrenthashmap 属于比较难的,大家需要简单看下源码,但是可以 不深入,就证明下你看过,了解下它是如何优化的。

1、counrrenthashmap 是如何实现线程安全的?可以简单说一下为了效率更快,比起 HashTable,counrrenthashmap 作了哪些优化吗?

2、平时我们会经常使用 HashMap,但是 counrrenthashmap 很少使用到,你可以简单说一下什么样的场景下使用 counrrenthashmap 吗?(指导:这个是个开放性问题,大家思考一下吧,千万不要只说 多线程 情况下使用 counrrenthashmap 哈,那样没有意义,因为有时候,线程的安全,可以由我们程序员来控制,不一定要使用 counrrenthashmap,所以需要大家思考一下)

共以下 7 个回答

  • Everglow 永久会员 2023年11月17日 上午1:01

    1、counrrenthashmap 是如何实现线程安全的?可以简单说一下为了效率更快,比起 HashTable,counrrenthashmap 作了哪些优化吗?

    JDK1.7是通过分段锁来保证线程安全的,它的底层是一个segment数组,segment继承了reentrantlock,是一种可重入锁,并且还维护了hashentry数组,来存放真实的数据,具体来说每次put数据时都会根据key计算出一个segment槽位,之后通过trylock方法获取锁,获取失败就进行自旋,获取成功就通过key再次计算hashentry数组中的槽位,之后的操作与HashMap基本一致,修改完成后释放掉锁。

    使用分段锁的方式,锁的粒度比较大在JDK1.8后采用synchronized和cas的方式来保证线程安全,并且锁的粒度缩小到一个哈希数组的槽位,底层和HashMap一样采用一个数组 + 链表/红黑树存储数据

    具体来说在put操作时首先通过key的哈希值计算在数组中的位置,如果当前槽位为空就通过cas的方式设置该节点设置失败就进行自旋,如果不为空则通过synchronized的方式进行修改

    2、平时我们会经常使用 HashMap,但是 counrrenthashmap 很少使用到,你可以简单说一下什么样的场景下使用 counrrenthashmap 吗?(指导:这个是个开放性问题,大家思考一下吧,千万不要只说 多线程 情况下使用 counrrenthashmap 哈,那样没有意义,因为有时候,线程的安全,可以由我们程序员来控制,不一定要使用 counrrenthashmap,所以需要大家思考一下)

    0 赞同 0 条回复
  • Silence 永久会员 2023年10月27日 下午11:04

    1 Concurrenthashmap,跟普通的hashmap相比,它主要是通过加锁的方式来实现的线程安全。一开始想让哈西map实现线程安全使用的是hash table来进行实现的,这个hash table它比较粗糙,他所的范围加的比较大,一个县城他就能锁住整张表,所以说同一时刻内只能有一个线程对这个海信map进行操作他的效率是非常非常低的。在DK 1.7版本的时候就出现了concurrenthashmap,他对于这个锁进行了一些优化,他使用了一个分段数来进行变法控制。他整个哈西map就变成了一个segment数组,一个Segment元素,又是一个小型的hashmap,他锁的单位就是所的这个segment元素。所以说这个segment数组的宽度就是他的并发度。然后到了DK 1.8版本之后又进一步做了优化,他舍弃了分段所的机制,所的所的力度直接变为了所每一个链表的表头,这样的话它的并发度就变得更高了,这个桶的个数就是它的并发度,同时他也并不会造成形成安全的问题。

    2 Concurrenthashmap的话,它可以做多线程下的共享缓存。就比如说我们没有出现Redis或者是memorcache的时候就可以用一个Concurrent hushmap来充当缓存.

    0 赞同 0 条回复
  • LilyBoy 永久会员 2023年9月11日 下午10:38

    counrrenthashmap jdk1.7之前的底层数据结构:segment+数组+链表的形式实现,通过加ReentranLock锁的方式来保证线性安全,也就是通过分段锁的形式;JDK1.8之后Node数组+数组+链表/红黑树的数据结构实现,类似于HashMap的数据结构,通过CAS、Synchronizd锁保证线性安全,做了优化;
    而HashTable得底层数据结构采用了数组+链表得形式,并且使用synchronized关键字来保证多线程情况下访问同步资源有序得访问,使用得是同一把锁,效率比较低;

    比如在输出不同日志级别得日志时,同一时间可以让多线程处理不同的日志,可以使用CorrentHashMap来解决。可以使用日志等级来作为key,线程安全的队列作为value。

    0 赞同 0 条回复
  • Gary 永久会员 2023年7月8日 下午4:35

    1.concurrentHashMap利用分段锁技术,基于CAS和synchronized,它不是一锁就锁整个数组,而是把锁的粒度细化到数组的每一个元素,这样的话,就可以有多个线程同时对一个concurrentHashMap进行读写操作,而不至于引发线程安全问题。如果有多个线程要在数组的同一个位置上操作,这个时候才会阻塞。只要哈希不冲突,就不会产生阻塞。
    hashTable只是在hashMap的基础上,每个方法都加了个synchronized,使得多线程下,只能一个个线程排队操作,效率很低。

    2.一个日志系统,需要输出不同级别的日志,同一时间,有多个线程一起输出。此时可以用concurrentHashMap来解决。用日志等级作为key,线程安全的队列作为value,例如LinkedBlockingQueue,保证先进先出的顺序

    0 赞同 0 条回复
  • 。 永久会员 2023年7月5日 下午1:18

    1.在jdk1.7中counrrenthashmap使用分段锁实现,每次操作需要锁住一段区间,在1.8中,基于hashMap和cas于synchronize进行优化,在插入元素时,如果槽位为空则通过cas插入,要是不为空且需要扩容,就协助扩容,否则通过synchronize锁住该槽位,相对于以前的版本和hashtable,锁粒度明显降低。
    2.在多个用户通过websocket保持长连接进行通信的情况下,需要使用counrrenthashmap存储用户对应的session和统计用户人数。

    0 赞同 0 条回复
  • 秊 永久会员 2023年6月22日 下午9:10

    1、counrrenthashmap 是如何实现线程安全的?可以简单说一下为了效率更快,比起 HashTable,counrrenthashmap 作了哪些优化吗?

    JDK 1.7 中 ConcurrentHashMap 使用了分段锁来实现线程安全。它的底层是一个 Segment 数组,每个 Segment 通过继承 ReetrantLock 来控制自己这部分的加锁。其中每个 Segment 就类似一个 HashTable,这样只要保证每个 Segment 是线程安全的,就能确保整个哈希表也是安全的了。

    JDK 1.8 为了摆脱哈希表中 Segment 个数对并发度的限制,底层采用和 HashMap 类似的实现:数组 + 链表 + 红黑树,加锁用 CAS 和 synchronized 实现。具体来说,在进行 put 操作时,如果槽位为空,则使用 CAS 插入新节点。如果槽位不为空,则需要进一步判断其它线程是否在对其扩容,是则协助扩容,不是则使用 synchronized 锁住当前槽位,再进行插入节点操作。

    2、平时我们会经常使用 HashMap,但是 counrrenthashmap 很少使用到,你可以简单说一下什么样的场景下使用 counrrenthashmap 吗?

    比如在日志分析时,可以将日志分成多个数据块,同时开启多个线程进行对日志进行并发处理,最终将结果汇总到 ConcurrentHashMap 中;再比如一个并发执行的多任务列表,可以用 ConcurrentHashMap 来作为任务管理的数据结构。任务为 Key,任务的执行状态为 Value,多个线程可以同时查找和更新任务的状态,实现对多任务的控制。

    0 赞同 0 条回复
  • 西西弗斯的石头 永久会员 2023年6月14日 下午1:29

    1.conrrenthashmap过去的版本是通过分段锁的形式实现线程安全,当一个线程占用一把锁segment访问其中一段数据时,位于其它segment的数据也可以被其它线程同时访问,每个segment分配子数组,将hashmap数组分成多个子数组,每个子数组分配一把锁,线程只有在获得某把分段锁的时候才能操作该子数组。JDK1.8以后conrrenthashmap采用CAS+synchronized的方式实现线程安全,基于hashmap的结构改造,与原来相比锁更细粒度化了,细化到了数组中的每个元素,sychronized只锁当前链表的首节点或树的根节点,只要哈希不冲突就不会发生并发,put元素时候通过hash计算出索引,发现索引对应的数组的位置为空,则使用CAS方式添加,添加失败则进入下次循环,如果发现对应数组位置不为空,则尝试获取头节点的同步锁再进行操作;
    2.可以用来分配任务并发执行,利用其并发能力,为每个任务分配一个独立的执行线程,从而提高任务效率,测试时候用到过,测试并发情况下插入的效率。

    0 赞同 0 条回复

# 回答此问题

后才能回答