Java基础六—Java集合框架Map

HashMap

HashMap使用hash数组+单链表实现,数组中的每个元素都是链表,由Node内部类实现,当链表长度超过8时,转化为红黑树。

HashMap实现了Map接口,即允许放入key为null的元素,也允许插入value为null的元素;除该类未实现同步外,其余跟Hashtable大致相同;
跟TreeMap不同,该容器不保证元素顺序,根据需要该容器可能会对元素重新哈希,元素的顺序也会被重新打散,因此不同时间迭代同一个HashMap的顺序可能会不同。
根据对冲突的处理方式不同(解决哈希冲突的方式),哈希表有两种实现方式,一种开放定址法(Open addressing),另一种是拉链冲突法(Separate chaining with linked lists)。

1.调用hash方法计算K的Hash值,结合数组长度,计算得到数组下标。
2.顺序遍历链表,equals()方法查找相同Node链表中的K值对应的V值。
hashCode是定位的,存储位置,equals是定性的,比较两者是否相等。

  • 多线程put操作后,get操作导致死循环
  • 多线程put非null元素后,get操作得到null值
  • 多线程put操作,导致袁术丢失

  • HashMap是采用链表解决Hash冲突,因为是链表结构,那么就很容易形成闭合的链路,这样在循环的时候只要有线程对这个HashMap进行get操作就会产生死循环。

  • 在单线程情况下,只有一个线程对HashMap的数据结构进行操作,是不可能产生闭合的回路的。
  • 那就只有在多线程并发的情况下才会出现这种情况,那就是在put操作的时候,如果size > initialCapacity * loadfactory,那么这时候HashMap就会进行rehash操作,随之HashMap的结构就会发生翻天覆地的变化。
    很有可能就是两个线程在这个时候同时触发了rehash操作,产生了闭合的回路(环形链表)。

TreeMap

基于红黑树实现

TreeMap实现了SortedMap接口,也就是说会按照key的大小顺序对Map中的元素进行排序,key大小的评判可以通过其本身的自然顺序(natural ordering),也可以通过构造时传入的比较器(Comparator)。

HashTable

和 HashMap 类似,但它是线程安全的,这意味着同一时刻多个线程可以同时写入 HashTable 并且不会导致数据不一致。它是遗留类,不应该去使用它。

现在可以使用 ConcurrentHashMap 来支持线程安全,并且 ConcurrentHashMap 的效率会更高,因为 ConcurrentHashMap 引入了分段锁。

同时满足HashMap和linked list的某些特性。可将LinkedHashMap看作采用linked list增强的HashMap。
使用双向链表来维护元素的顺序,顺序为插入顺序或者最近最少使用(LRU)顺序。

ConcurrentHashMap

为什么HashTable慢
Hashtable之所以效率低下主要是因为其实现使用了synchronized关键字对put等操作进行加锁,而synchronized关键字加锁是对整个对象进行加锁,也就是说在进行put等修改Hash表的操作时,锁住了整个Hash表,从而使得其表现的效率低下。

在JDK1.5~1.7版本,Java使用了分段锁机制实现ConcurrentHashMap.

简而言之,ConcurrentHashMap在对象中保存了一个Segment数组,即将整个Hash表划分为多个分段;而每个Segment元素,即每个分段则类似于一个Hashtable;
这样,在执行put操作时首先根据hash算法定位到元素属于哪个Segment,然后对该Segment加锁即可。
因此,ConcurrentHashMap在多线程并发编程中可是实现多线程put操作。

核心参数 concurrencyLevel:
并行级别、并发数、Segment 数,怎么翻译不重要,理解它。默认是 16,也就是说 ConcurrentHashMap 有 16 个 Segments,所以理论上,这个时候,最多可以同时支持 16 个线程并发写,只要它们的操作分别分布在不同的 Segment 上。
这个值可以在初始化的时候设置为其他值,但是一旦初始化以后,它是不可以扩容的。

在JDK1.7之前,ConcurrentHashMap是通过分段锁机制来实现的,所以其最大并发度受Segment的个数限制。
因此,在JDK1.8中,ConcurrentHashMap的实现原理摒弃了这种设计,而是选择了与HashMap类似的数组+链表+红黑树的方式实现,而加锁则采用CAS和synchronized实现。

WeakHashMap,从名字可以看出它是某种 Map。它的特殊之处在于 WeakHashMap 里的entry可能会被GC自动删除,即使程序员没有调用remove()或者clear()方法。
更直观的说,当使用 WeakHashMap 时,即使没有显示的添加或删除任何元素,也可能发生如下情况:

  • 调用两次size()方法返回不同的值;
  • 两次调用isEmpty()方法,第一次返回false,第二次返回true;
  • 两次调用containsKey()方法,第一次返回true,第二次返回false,尽管两次使用的是同一个key;
  • 两次调用get()方法,第一次返回一个value,第二次返回null,尽管两次使用的是同一个对象。

WeakHashMap 的这个特点特别适用于需要缓存的场景。
在缓存场景下,由于内存是有限的,不能缓存所有对象;对象缓存命中可以提高系统效率,但缓存MISS也不会造成错误,因为可以通过计算重新得到。

要明白 WeakHashMap 的工作原理,还需要引入一个概念 : 弱引用(WeakReference)。我们都知道Java中内存是通过GC自动管理的,GC会在程序运行过程中自动判断哪些对象是可以被回收的,并在合适的时机进行内存释放。
GC判断某个对象是否可被回收的依据是,是否有有效的引用指向该对象。如果没有有效引用指向该对象(基本意味着不存在访问该对象的方式),那么该对象就是可回收的。这里的有效引用 并不包括弱引用。
也就是说,虽然弱引用可以用来访问对象,但进行垃圾回收时弱引用并不会被考虑在内,仅有弱引用指向的对象仍然会被GC回收。

WeakHashMap 内部是通过弱引用来管理entry的,弱引用的特性对应到 WeakHashMap 上意味着什么呢?
将一对key, value放入到 WeakHashMap 里并不能避免该key值被GC回收,除非在 WeakHashMap 之外还有对该key的强引用。

Original: https://www.cnblogs.com/winter0730/p/15329690.html
Author: cos晓风残月
Title: Java基础六—Java集合框架Map

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/576248/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • logrotate command in Linux

    背景 在生产过程中,由于磁盘空间、保留周期等因素,会对系统、应用等日志提出要求,要求系统日志定期进行轮转、压缩和删除,从而减少开销,而系统自带的 logrotate 则是一个简单又…

    数据库 2023年6月14日
    0170
  • 实时人流量监测——海康威视sdk初体验

    本文主要是博主使用海康SDK进行人流量统计的摸索过程,在这里简单记录一下。 查询文档,能实现人流量统计大概有两种方式,报警或者监听, 这边我选择了监听方式,NET_DVR_Star…

    数据库 2023年6月16日
    0164
  • Git的常见命令

    Git 一、git环境安装 1.初始化本地仓库: git init 2.将本地仓库跟远程仓库建立连接:git remote add name path ​ git clone pa…

    数据库 2023年6月16日
    082
  • XPath和Selenium的使用

    XPath 是一门在 XML 文档中查找信息的语言 /: ——># 从根节点选取: //: ——># 不管位置,直接找 /@属性名 ——># 获取对应属性值 /t…

    数据库 2023年6月9日
    075
  • MySQL之多表查询、Navicat及pymysql

    一、多表查询 1.1 数据准备 — 建表 create table dep( id int primary key auto_increment, name varchar(20…

    数据库 2023年5月24日
    095
  • Component name “Login“ should always be multi-word

    在运行vue项目的时候,看到此提示 这是因为没有关闭elint提示的错误,在vue.config.js下添加代码 lintOnSave: false Original: https…

    数据库 2023年6月11日
    081
  • SpringBoot下的文件上传

    ; 代码很简单。已经放到码云了,码云地址:https://gitee.com/zhang-zhixi/springboot-upload.git posted @2022-04-2…

    数据库 2023年6月14日
    080
  • Linux_连接工具_SecureCRT的使用教程

    什么是SecureCRT? SecureCRT是一款支持 SSH2、SSH1、Telnet、Telnet/SSH、Relogin、Serial、TAPI、RAW 等协议的终端仿真程…

    数据库 2023年6月11日
    0119
  • leetcode 513. Find Bottom Left Tree Value 找树左下角的值 (简单)

    给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root = [2,1,3]输出: 1 示例 2…

    数据库 2023年6月16日
    086
  • Podman部署及应用

    点击查看代码 什么是podman Podman是一个开源项目,可在大多数Linux平台上使用并开源在GitHub上。Podman是一个无守护进程的容器引擎,用于在Linux系统上开…

    数据库 2023年6月14日
    073
  • 正则表达式

    1.正则表达式分类 正则表达式:REGEXP,REGular EXPression。正则表达式分为两类: Basic REGEXP(基本正则表达式) Extended REGEXP…

    数据库 2023年6月15日
    091
  • Pisa-Proxy 之 SQL 解析实践

    SQL 语句解析是一个重要且复杂的技术,数据库流量相关的 SQL 审计、读写分离、分片等功能都依赖于 SQL 解析,而 Pisa-Proxy 作为 Database Mesh 理念…

    数据库 2023年6月16日
    0122
  • keycloak~资源的远程授权

    17.1远程资源授权准备 17.1.1认证和访问流程图 参考:http://www.zyiz.net/tech/detail-141309.html 17.1.2为用户指定角色 可…

    数据库 2023年6月6日
    086
  • SQL语句的整合

    基础语法 https://blog.csdn.net/m0_37989980/article/details/103413942 CRUD 提供给数据库管理员的基本操作,CRUD(…

    数据库 2023年6月14日
    076
  • leetcode 669. Trim a Binary Search Tree 修剪二叉搜索树 (简单)

    一、题目大意 给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变…

    数据库 2023年6月16日
    088
  • JUC学习笔记(六)

    JUC 中提供了三种常用的辅助类,通过这些辅助类可以很好的解决线程数量过多时 Lock 锁的频繁操作。这三种辅助类为: CountDownLatch: 减少计数 CyclicBar…

    数据库 2023年6月6日
    098
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球