2、Map(HashTable、LinkedHashMap、HashMap、TreeMap、ConcurrentHashMap)

本文详细探讨了Java中的Map接口实现,尤其是HashMap、HashTable和ConcurrentHashMap的区别与工作原理。HashMap是线程不安全的,1.8版引入红黑树以提高性能,当链表长度超过8时转换为红黑树。HashTable通过synchronized实现线程安全,而ConcurrentHashMap使用更为精细的锁策略。此外,文章还讨论了HashMap的扩容机制、负载因子和哈希冲突解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2、Map(K-V 对)

2.1、概述

  1. a、HashMap( HashMap 的实现原理?

    底层数据结构,JDK 1.8 是数组 + 链表 + 红黑树,JDK 1.7 无红黑树。链表长度大于 8 时,转化为红黑树,优化查询效率。
    初始容量为 16,通过 tableSizeFor 保证容量为 2 的幂次方。寻址方式,高位异或,(n-1)&h 取模,优化速度。
    扩容机制,当元素数量大于容量 x 负载因子 0.75 时,容量扩大为原来的 2 倍,新建一个数组,然后转移到新数组。

  2. b、基于 Map 实现。

    线程不安全。

  3. c、HashMap (1.7) 多线程循环链表问题

    在多线程环境下,进行扩容时,1.7 下的 HashMap 会形成循环链表。
    怎么形成循环链表: 假设有一 HashMap 容量为 2 , 在数组下标 1 位置以 A -> B 链表形式存储。有一线程对该 map 做 put 操作,由于触发扩容条件,需要进行扩容。这时另一个线程也 put 操作,同样需要扩容,并完成了扩容操作,由于复制到新数组是头部插入,所以 1 位置变为 B -> A 。这时第一个线程继续做扩容操作,首先复制 A ,然后复制 B ,再判断 B.next 是否为空时,由于第二个线程做了扩容操作,导致 B.next = A,所以在将 A 放到 B 前,A.next 又等于 B ,导致循环链表出现。

  4. d、HashTable

    线程安全,方法基本全用 Synchronized 修饰。
    初始容量为 11 ,扩容为 2n + 1 。
    继承 Dictionary 类。

  5. e、ConcurrentHashMap

    线程安全的 HashMap。

    1.7 采用分段锁的形式加锁;1.8 使用 Synchronized 和 CAS 实现同步,若数组的 Node 为空,则通过 CAS 的方式设置值,不为空则加在链表的第一个节点。获取第一个元素是否为空使用 Unsafe 类提供的 getObjectVolatile 保证可见性。
    对于读操作,数组由 volatile 修饰,同时数组的元素为 Node,Node 的 K 使用 final 修饰,V 使用 volatile 修饰,下一个节点也用 volatile 修饰,保证多线程的可见性。

  6. f、LinkedHashMap
    LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。

  7. TreeMap

    有序的 Map,红黑树结构,可以自定义比较器来进行排序。

  8. h、Collections.synchronizedMap 如何实现 Map 线程安全?

​ 基于 Synchronized ,实际上就是锁住了当前传入的 Map 对象。

2.1.2、Map的操作

在这里插入图片描述

在这里插入图片描述

2.2、HashMap

源码分析:

首先HashMap实现了Map接口

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值