Map及其实现类、锁

news2024/11/28 14:41:09

HashMap、HashTable、ConcurrentHashMap 区别


一.HashMap和HashTable的区别

1、两者父类不同

HashMap是继承自AbstractMap类,而Hashtable是继承自Dictionary类。不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口。

2、对外提供的接口不同

Hashtable比HashMap多提供了elments() 和contains() 两个方法

  • elments() 方法继承自Hashtable的父类Dictionnary。elements() 方法用于返回此Hashtable中的
    value的枚举。
  • contains()方法判断该Hashtable是否包含传入的value。它的作用与containsValue()一致。事实上,contansValue() 就只是调用了一下contains() 方法。

3、对null的支持不同

  • Hashtable:key和value都不能为null。
  • HashMap:key可以为null,但是这样的key只能有一个,因为必须保证key的唯一性;可以有多个key值对应的value为null。

4、安全性不同

  • HashMap是线程不安全的,在多线程并发的环境下,可能会产生死锁等问题,因此需要开发人员自己处理多线程的安全问题。
  • Hashtable是线程安全的,它的每个方法上都有synchronized 关键字,因此可直接用于多线程中。
  • 虽然HashMap是线程不安全的,但是它的效率远远高于Hashtable,这样设计是合理的,因为大部分的使用场景都是单线程。
  • ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁(JDK1.7),并不对整个数据进行锁定。当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。

5、初始容量大小和每次扩充容量大小不同

6、计算hash值的方法不同


二.ConcurrentHashMap 和 Hashtable 的区别

ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的⽅式上不同

1. 底层数据结构

  • ConcurrentHashMap : JDK1.7 的 ConcurrentHashMap 底层采⽤ 分段的数组+链表 实现,JDK1.8采⽤的数据结构跟 HashMap1.8 的结构⼀样,数组+链表+红⿊树
  • Hashtable :JDK1.8 之前的 HashMap 的底层数据结构类似都是采⽤ 数组+链表 的形式,数组是HashMap 的主体,链表则是主要为了解决哈希冲突⽽存在的;

2.实现线程安全的⽅式(重要)

  • ConcurrentHashMap :在 JDK1.7 的时候, ConcurrentHashMap (分段锁)对整个桶数组进⾏了分割分段( Segment ),每⼀把锁只锁容器其中⼀部分数据,多线程访问容器⾥不同数据段的数据,就不会存在锁竞争,提⾼并发访问率。 到了 JDK1.8 的时候已经摒弃了 Segment 的概念,⽽是直接⽤ Node 数组+链表+红⿊树的数据结构来实现,并发控制使⽤ synchronized 和 CAS 来操作。
  • Hashtable (同⼀把锁) :使⽤ synchronized 来保证线程安全,效率⾮常低下。当⼀个线程访问同步⽅法时,其他线程也访问同步⽅法,可能会进⼊阻塞或轮询状态,如使⽤ put 添加元素,另⼀个线程不能使⽤ put 添加元素,也不能使⽤ get,竞争会越来越激烈效率越低。

三.Map

  • HashMap :稍后详细介绍
  • LinkedHashMapLinkedHashMap 继承⾃ HashMap ,所以它的底层仍然是基于拉链式散列结构即由数组+链表|红⿊树组成。另外, LinkedHashMap 在上⾯结构的基础上,增加了⼀条双向链表,使得上⾯的结构可以保持键值对的插⼊顺序。同时通过对链表进⾏相应的操作,实现了访问顺序相关逻辑
  • Hashtable : 数组+链表组成的。
  • TreeMap红⿊树(⾃平衡的排序⼆叉树

四.简述synchronized

  1. 对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现
  2. 底层原理:Synchronized进过编译,会在同步块的前后分别形成monitorentermonitorexit这个两个字节码指令。在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计算器加1,相应的,在执行monitorexit指令时会将锁计算器就减1当计算器为0时,锁就被释放了。如果获取对象锁失败,那当前线程就要阻塞(悲观锁代表),直到对象锁被另一个线程释放为止。

五.SynchronizedMap和ConcurrentHashMap有什么区别?

  • SynchronizedMap()和Hashtable一样,实现上在调用map所有方法时,都对整个map进行同步。所以,只要有一个线程访问map,其他线程就无法进入map,
  • ConcurrentHashMap的实现却更加精细,它对map中的所有桶加了锁。而如果一个线程在访问ConcurrentHashMap某个桶时,其他线程,仍然可以对map执行某些操作。
  • 所以,ConcurrentHashMap在性能以及安全性方面,明显比Collections.synchronizedMap()更加有优势。同时,同步操作精确控制到桶,这样,即使在遍历map时,如果其他线程试图对map进行数据修改,也不会抛出ConcurrentModificationException。

六.HashMap详解

1)基本数据结构

  • 1.7 数组 + 链表
  • 1.8 数组 + (链表 | 红黑树)

2)树化与退化

树化意义

  • 红黑树用来避免 DoS 攻击,防止链表超长时性能下降,树化应当是偶然情况,是保底策略
  • hash 表的查找,更新的时间复杂度是 O ( 1 ) O(1) O(1),而红黑树的查找,更新的时间复杂度是 O ( l o g 2 ⁡ n ) O(log_2⁡n) O(log2n),TreeNode 占用空间也比普通 Node 的大,如非必要,尽量还是使用链表
  • hash 值如果足够随机,则在 hash 表内按泊松分布,在负载因子 0.75 的情况下,长度超过 8 的链表出现概率是 0.00000006,树化阈值选择 8 就是为了让树化几率足够小

树化规则

  • 当链表长度超过树化阈值 8 时,先尝试扩容来减少链表长度,如果数组容量已经 >=64,才会进行树化

退化规则

  • 情况1:在扩容时如果拆分树时,树元素个数 <= 6 则会退化链表
  • 情况2:remove 树节点时,若 root、root.left、root.right、root.left.left 有一个为 null ,也会退化为链表

3)索引计算

索引计算方法

  • 首先,计算对象的 hashCode()
  • 再进行调用 HashMap 的 hash() 方法进行二次哈希
    • 二次 hash() 是为了综合高位数据,让哈希分布更为均匀
  • 最后 & (capacity – 1) 得到索引

数组容量为何是 2 的 n 次幂

  1. 计算索引时效率更高:如果是 2 的 n 次幂可以使用位与运算代替取模
  2. 扩容时重新计算索引效率更高: hash & oldCap == 0 的元素留在原来位置 ,否则新位置 = 旧位置 + oldCap

注意

  • 二次 hash 是为了配合 容量是 2 的 n 次幂 这一设计前提,如果 hash 表的容量不是 2 的 n 次幂,则不必二次 hash
  • 容量是 2 的 n 次幂 这一设计计算索引效率更好,但 hash 的分散性就不好,需要二次 hash 来作为补偿,没有采用这一设计的典型例子是 Hashtable

4)put 与扩容

put 流程

  1. HashMap 是懒惰创建数组的,首次使用才创建数组
  2. 计算索引(桶下标)
  3. 如果桶下标还没人占用,创建 Node 占位返回
  4. 如果桶下标已经有人占用
    1. 已经是 TreeNode 走红黑树的添加或更新逻辑
    2. 是普通 Node,走链表的添加或更新逻辑,如果链表长度超过树化阈值,走树化逻辑
  5. 返回前检查容量是否超过阈值,一旦超过进行扩容

1.7 与 1.8 的区别

  1. 链表插入节点时,1.7 是头插法,1.8 是尾插法

  2. 1.7 是大于等于阈值且没有空位时才扩容,而 1.8 是大于阈值就扩容

  3. 1.8 在扩容计算 Node 索引时,会优化
    在这里插入图片描述

扩容(加载)因子为何默认是 0.75f
4. 在空间占用与查询时间之间取得较好的权衡
5. 大于这个值,空间节省了,但链表就会比较长影响性能
6. 小于这个值,冲突减少了,但扩容就会更频繁,空间占用也更多

5)key 的设计

key 的设计要求

  1. HashMap 的 key 可以为 null,但 Map 的其他实现则不然
  2. 作为 key 的对象,必须实现 hashCode 和 equals,并且 key 的内容不能修改(不可变)
  3. key 的 hashCode 应该有良好的散列性

补充

1.悲观锁和乐观锁 CAS

2.Synchronized ReentrantLock SynchronizedMap ConcurrentHashMap

3.wait sleep lock synchronized volatile

参考之前的文章

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/26775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

朱松纯教授场景理解相关文章简介

朱松纯教授场景理解相关文章简介 Holistic 3D Scene Parsing and Reconstruction from a Single RGB Image 基于单张图像的整体场景解译与重建 我们提出了一个计算框架来联合解译单帧RGB图像&#xff0c;通过使用一系列的随机语法模型生成的CAD模型构成整体的3D结构。具体地说…

智慧农业SaaS系统

真正的大师,永远都怀着一颗学徒的心&#xff01; 一、项目简介 智慧农业SaaS系统 二、实现功能 监控管理&#xff1a;支持海康摄像头监控。 用户管理&#xff1a;支持用户是系统操作者&#xff0c;该功能主要完成系统用户配置。 岗位管理&#xff1a;支持配置系统用户所属担…

bugku渗透测试 1 writeup(无需VPS)

靶场地址&#xff1a;BugKu渗透测试1 该靶场只需要20金币就可以开启两小时&#xff0c;算的上非常良心实惠了&#xff0c;趁着有空赶紧刷一刷题目 目录 第一场景&#xff1a; 第二场景&#xff1a; 第三场景&#xff1a; 第四场景&#xff1a; 第五场景&#xff1a; 第六…

第五章:面向对象(上)

第五章&#xff1a;面向对象(上) 5.1&#xff1a;面向过程与面向对象 面向过程(POP)与面向对象(OOP) ​ 二者都是一种思想&#xff0c;面向对象是相对于面向过程而言的。面向过程&#xff0c;强调的是功能行为&#xff0c;以函数为最小值&#xff0c;考虑怎么做。面向对象&…

【BOOST C++ 线程】boost::thread库的基本使用方法总结

一、说明 boost::thread的六种使用方法总结&#xff0c;本文初步介绍线程的函数、构造、执行的详细解释。 二、boost::thread的几个函数 函数功能join()让主进程等待子线程执行完毕后再继续执行get_id()获得线程的 id 号detach()标线程就成为了守护线程&#xff0c;驻留后台运…

【项目实战:核酸检测平台】第二章 大卸八块

本章目标 完成项目架构设计和数据库结构设计 重点&#xff1a;全是重点 文章目录本章目标总体设计&#xff08;架构设计&#xff09;技术选型部署结构设计工程文档结构设计第一步&#xff1a;项目和模块命名第二步&#xff1a;约定项目工程文件内容第三步&#xff1a;设计文档…

Hadoop高可用环境搭建-HDFSNameNode高可用搭建、Yarn高可用搭建

本文环境搭建的前提条件&#xff1a;JDK、Zookeeper、Hadoop完全分布式环境搭建完成。如果未满足条件且不会搭建&#xff0c;可以前往博主的主页搜索相关文章进行搭建。 目录 一、HDFSNameNode高可用搭建 二、 Yarn高可用搭建 本文主节点hostname&#xff1a;master&#xff0c…

安装semantic segmentation editor

两天啊&#xff0c; 整整两天&#xff0c;知道这两天我是怎么过的吗&#xff1f;&#xff1f;1 步骤概述&#xff08;以下命令行都是在管理员条件下执行&#xff09;1.1 安装choco1.2 安装meteor1.3 安装semantic segmentation editor2过程3 我还是用Ubuntu安装过3.1Window安装…

【Mysql】主从一致

【Mysql】主从一致&#xff08;一&#xff09;主从复制【1】什么是主从复制【2】为什么需要主从复制【3】mysql复制原理【4】具体步骤【5】mysql主从形式【6】具体操作过程&#xff08;1&#xff09;首先在虚拟机服务器上安装mysql&#xff0c;进行简单的配置&#xff08;2&…

力扣(LeetCode)38. 外观数列(C++)

双指针模拟 初始字符串 sss 已给定&#xff0c;根据 sss 构造下一个外观数列 ttt &#xff0c;构造完毕&#xff0c; ststst &#xff0c;循环 n−1n-1n−1 次&#xff0c;构造出一个外观数列。 构造步骤 : 令 jjj 指向当前元素 &#xff0c; kkk 从 jjj 往右&#xff0c;记录…

新库上线 | CnOpenData招聘公司基本信息扩展数据

招聘公司基本信息扩展数据 一、数据简介 线上招聘是指各公司将其岗位需求、工作地点能力要求和薪酬等招聘信息发布在互联网上&#xff0c;供求职者参考&#xff0c;以线上的方式进行招聘。线上招聘网站是通过互联网相关技术&#xff0c;集结这些线上招聘信息&#xff0c;帮助雇…

Linux下自动删除过期备份和自动异地备份的脚本

每天自动删除过期备份 首先编写一个简单的Shell脚本DeleteExpireBackup.sh&#xff1a; 1 2 3 4 5 6 7 #!/bin/bash # 修改需要删除的路径 location"/database/backup/" # 删除最后修改时间为30天以前的备份文件夹 find $location -mtime 30 -type d | xargs rm …

3dmax渲染大图有斑点怎么办?

嗨喽大家好&#xff0c;经常有后台私信问&#xff1a;3dmax渲染大图老是有斑点怎么办&#xff1f;而且斑点有白色的&#xff0c;还有绿色、黑色甚至彩色。怎么去除这些斑点呢&#xff1f; 其实以上的常见的斑点问题&#xff0c;大部分是灯光设置的问题。今天我们便来盘点下下面…

第二章:字节码指令集与解析案例

一、概述执行模型字节码与数据类型字节码指令分类加载与存储指令局部变量压栈指令常量入栈指令出栈装入局部变量表指令算术运算指令代码举例一代码举例二代码举例三&#xff1a;i 和 i 的区别比较指令的说明类型转换指令宽化类型转换(Widening Numeric Conversions)窄化类型转换…

指纹浏览器是什么?可以用来解决跨境电商的什么问题?

如果你是跨境电商中的一员&#xff0c;那我相信你肯定不陌生指纹浏览器吧&#xff01;毕竟指纹浏览器可以说是每个跨境人必备的工具了&#xff0c;更别说它的一系列功能简直是为跨境电商商家量身打造的&#xff01; 龙哥作为跨境老手&#xff0c;对指纹浏览器不要太熟悉&#x…

葡萄糖-顺铂Glucose-cisplatin|葡萄糖-聚乙二醇-顺铂cisplatin-PEG-Glucose

葡萄糖-顺铂Glucose-cisplatin|葡萄糖-聚乙二醇-顺铂cisplatin-PEG-Glucose 中文名称&#xff1a;葡萄糖-顺铂 英文名称&#xff1a;Glucose-cisplatin 别称&#xff1a;生物素修饰葡萄糖&#xff0c;生物素-葡萄糖 PEG接枝修饰葡萄糖 葡萄糖-聚乙二醇-顺铂 cisplatin-PE…

Go:命令行参数解析包 flag 简介

文章目录示例运行小结在 Golang 程序中有很多种方法来处理命令行参数。简单的情况下可以不使用任何库&#xff0c;直接处理 os.Args&#xff1b;其实 Golang 的标准库提供了 flag 包来处理命令行参数&#xff1b;还有第三方提供的处理命令行参数的库&#xff0c;比如 Pflag 等。…

【附源码】计算机毕业设计JAVA研究生推免系统

【附源码】计算机毕业设计JAVA研究生推免系统 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA myba…

期货开户手机APP有哪些?

一、文华随身行 随身行是文华财经旗下APP软件&#xff0c;提供行情、图表、交易、行情讨论等综合服务。随身行是主流的期货交易软件&#xff0c;已接通全国139家期货公司 不过目前使用文华随身行APP是需要付费的&#xff0c;是直接向软件公司付费&#xff0c;与期货公司无关&…

2022 裁员风潮着实有点大,席卷全球~

近期无论国内外&#xff0c;裁员新闻接连不断&#xff0c;这次裁员风&#xff0c;给人的感觉&#xff0c;像是全球所有公司达成了 “某种协议”&#xff0c;行动上高度一致&#xff0c;开始接二连三的裁员&#xff0c;以往每年各个公司都有裁员&#xff0c;只是比例很小&#x…