HashMap和ConCurrentHashMap各自的相关特性和区别(浅谈)

浅谈一下HashMap和conCurrentHashMap的区别和各自的相关特性。主要是为了自己复习一下这个集合。打好基础。



首先。HashMap。众所周知,他是键值对<K , V>集合框架。

注意一点的是:hashMap是可以使用null作为键(K)和值(V)的。


hashMap的底层本质上是数组和链表。此话怎么说呢?

首先我们得了解hashMap是怎么存储数据的。”hashMap“,那么自然跟哈希离不开关系了。

我们先取键(K)的hash值。然后根据hash值计算得出它相应的存储位置。所以说。HashMap的查询效率也是相当高的。

那么既然说到存储位置,就不得不提HashMap中两个非常重要的参数:

static final int DEFAULT_INITIAL_CAPACITY     //默认桶数组长度
static final float DEFAULT_LOAD_FACTOR        //默认负载因子的大小
看到上边两行参数。可能有些朋友就疑问了,桶数组是什么东西,为什么叫”桶“。看来程序员的审美也不咋地。好吧。开个玩笑,我开头说了,HashMap集合的本质是数组和链表,这个数组指的就是桶数组。至于他为什么叫桶数组,我们就不要纠结这个问题了。


桶数组的默认大小是16,负载因子的默认大小是0.75f。

在我还没有了解HashMap之前,当然,现在我同样不算很了解它。

新手总是喜欢这么使用HashMap:

                               Map< K , V > map = new HashMap< K , V >()   //创建一个map对象。

这也没错。但是HashMap它可是提供了以下三种构造方法设置参数来创建HashMap的。

	(1)new HashMap(int capacity)  //设置桶数组大小
	(2)new HashMap(int capacity,int 
LOAD_FACTOR) //设置桶数组大小,负载因子
	    
(3)new HashMap()  //默认


所以说,在实际开发的时候,要根据具体业务具体需求设置合适的桶数组大小和负载因子。这是为了防止在项目实际上线运行中,HashMap多次rehash带来的负担。

讲到这里,那么有人会问了,rehash是什么?

在这里若想理解rehash是什么。

首先,桶数组大小默认为16,举个例子。现在有一栋贸易办公大厦,这栋大厦的一楼处有16个电梯,并且假设电梯内的空间无限大(这栋大楼真有钱,啧啧...)。这16个楼梯分别只能上不同的具有不同股票代码(这里的股票代码暂且比拟做hashCode值)的公司。

那么现在有20人来到这准备搭电梯去上班,假设A白领去A电梯,他通过他自身的公司证件号(这里的公司证件号可以比拟为通过键去到的hashCode值)正确验证并定位到A电梯,那么他就成功进入A电梯了。

B白领这时候通过他的证件号也是定位到了A电梯,然后怎么办呢?我刚开始说了,HahMap的底层本质是数组和链表,所以说,B直接就进入A电梯中,在A电梯里面,B白领排到A白领的后面。

这样比喻,大概了解了吧。16个电梯就是16个数组,数组里面,是个链表。


这时候,我要提出一个新问题了。假设现在这栋贸易大厦上某个公司分裂了。变成两个公司了。并且赌气说以后不一起搭同一个电梯上班。那么这时候,是不是16个电梯已经满足不了需求了。依照我们编程的经验,既然16个不够,那就扩大到17个呗。     

其实,说到这里,大家不知道还记得没有,我在一开始的时候说HashMap有两个很重要的参数,可是写到现在我只讲了桶数组大小。。对。还有一个负载因子load_factor。它的默认值是0.75f。它的作用又是什么呢?

它就像是一个"预警器"。此话怎讲。还是讲回刚才那个例子。作为这栋贸易大厦的管理者。他不可能等到16个都满了才想到要去增加。那时候增加的话建造电梯还要时间,但是需求就是现在要。所以说,这个0.75f就是预警器。16*0.75=12。也就是说。当12个数组都有数据填入了。那么这个hashMap就知道了,桶数组大小可能不够用了。要扩容了。所以说。不会等到16个数组都填了才扩容。

hashMap的扩容和许多java对象一样,翻倍增加。也就是说第一次扩容。会从16增加到32,第二次64,...


既然扩容了,假设前面放入的12个数据都依次放在了不同的数组中,则在第13个放入之前,桶数组增大变为32个,数据通过hashCode定位的信息全部失效。之前放入的12个数据全都要重新计算后再定位存储。这个过程就叫做rehash。

说白了,如果说要放入hashMap中的数据量少的话,还能接受,若是说,放入hashMap中的值是上百万个键值对呢。那么在这个过程中,他就要无数次扩容、rehash、扩容、rehash、扩容、rehash。这对于服务器来说负担是巨大的。所以说,在创建HashMap时根据具体业务需求指定适合的桶数组大小和负载因子大小是多么重要。

--------------------------------------优雅的分割线------------------------------------------



同时。HashMap又是一个无序的集合。如果想要使用这种键值对的结构存储数据,又想要有序。可以使用LinkedHashMap。你们可以查一下API文档看看。


----------------------------------又是一道分割线------------------------------------------------


再者,HashMap是线程不安全的。及如果设计到写操作时,会很容易发生数据丢失的情况。这一点要格外注意。那么如果我们在这种背景下。还想要使用这种键值对的结构,但是又想要线程安全这种两全其美的办法有没有呢?


办法是有的。这里有三种解决方案。

(1)Map map = Collections.synchronizedMap(new HashMap( ));

(2)Map map = new HashTable( );

(3)Map map = new ConCurrentHashMap( );

第一种无非就是额外给HashMap加个锁就是了。

第二种的话。是在其底层就已经有写入了锁这个数据结构了。但是,遗憾的是,HashTable是只有一把锁,所以说它的效率非常低下。已经被淘汰。

第三种就是目前来说,主流的一种线程安全的Map。它和HashTable的区别就是。ConCurrentHashMap具有很多把锁。我们称它为分段锁。它的底层有很多个类对象,叫做Segment。这个类对象是什么呢?我们可以理解为它相当于HashTable,每个Segment中都有一把锁。当一个线程访问其其中一个Segment时,其他线程可以访问ConCurrentHashMap中的其他Segment,且不会受影响,彼此之间互相独立。ConCurrentHashMap和HashTable的区别就在于细粒度的控制上。



笔记完毕。这是我一点浅显的了解。若是哪里说得不对,或者说得不好的地方。大家谅解。敬请大家一起讨论交流。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: HashMapConcurrentHashMap都是Java中的Map实现,用于存储键值对数据。它们之间的主要区别在于线程安全性和并发性。 HashMap是非线程安全的,因此在多线程环境下使用可能会导致不一致的结果。而ConcurrentHashMap是线程安全的,它使用了锁分离技术和分段锁来保证并发性和线程安全性。 在使用上,HashMap适用于单线程环境或者多线程环境中不需要并发访问的场景。而ConcurrentHashMap则适用于多线程环境中需要高并发访问的场景。 另外,ConcurrentHashMap相对于HashMap还有一些额外的方法,比如putIfAbsent()和replace()等,用于更方便地进行并发操作。 总之,选择HashMap还是ConcurrentHashMap要根据实际情况进行考虑,根据需求选择适合的实现方式。 ### 回答2: HashMapConcurrentHashMap都是Java中的集合类,它们的区别主要体现在线程安全性和并发控制方面。 1. 线程安全性: HashMap是非线程安全的,多个线程同时访问和修改同一个HashMap实例会导致数据不一致或出现异常。 ConcurrentHashMap是线程安全的,它使用锁分段技术来保证多个线程可以同时访问不同的分段,从而提高并发性能。多个线程可以同时读取其中的数据,但对数据的修改操作会通过锁机制保证线程安全。 2. 并发控制: HashMap的并发控制是通过外部手段进行的,即通过在多线程环境下保证对HashMap的访问操作是互斥的,比如使用synchronized关键字或使用Lock接口。这样会导致多个线程在同一时刻只能有一个线程可以对HashMap进行操作,从而降低并发性能。 ConcurrentHashMap内部使用了分段锁技术,它将整个数据集分成多个小段,每个小段有一个独立的锁,不同的线程可以同时对不同的小段进行修改操作。这样多个线程可以并发的进行读取和修改操作,提高了并发性能。 总的来说,HashMap适用于单线程环境或者多线程环境但是不存在并发修改的场景,而ConcurrentHashMap适用于多线程并发修改的场景。但是需要注意的是,由于ConcurrentHashMap在并发控制方面做了额外的工作,因此在某些情况下会比HashMap的效率略低,所以在选择使用时需要根据具体的应用场景进行判断。 ### 回答3: HashMapConcurrentHashMap都是Java中的Map接口的实现类,它们之间有几个主要的区别: 1. 线程安全性:HashMap是非线程安全的,而ConcurrentHashMap是线程安全的。在多线程环境下,如果多个线程同时对HashMap进行操作,可能会导致数据不一致或者出现异常。而ConcurrentHashMap通过使用锁分段技术来保证高并发情况下线程安全。 2. 性能:在单线程环境下,HashMap的性能优于ConcurrentHashMap。因为ConcurrentHashMap为了保证线程安全性,会引入额外的开销,比如使用锁来保证操作的原子性。但是在高并发环境下,ConcurrentHashMap的性能优于HashMap,因为ConcurrentHashMap可以支持多个线程同时进行读操作,而不需要进行同步操作。 3. 数据一致性:HashMap的数据一致性是弱一致性的,即在多线程环境下无法保证数据的实时一致性。而ConcurrentHashMap使用一种叫做"读写分离"的技术,能够保证读操作之间的一致性,但是读操作和写操作之间仍然存在一定的时间间隔。 4. 并发度:ConcurrentHashMap支持更高的并发度。在ConcurrentHashMap中,它的数据结构是由多个Segment(分段锁)组成的,每个Segment中包含一个HashEntry数组,每个HashEntry是一个链表。不同的线程可以同时对不同的Segment进行读写操作,从而提高了并发度。 综上所述,HashMap适用于单线程环境下对数据的读写操作,而ConcurrentHashMap适用于高并发环境下对数据的读写操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值