java集合总结
1.常见集合
- Collection
- List:有序可重复集合,可直接根据元素的索引来访问
- Vector-Stack
- ArrayList
- LinkedList
- Queue:队列集合
- Deque-LinkedList、ArrayDeque
- PriorityQueue
- Set:无序不可重复集合,只能根据元素本身来访问
- Hashset-LinkedHashSet
- SortedSet-TreeSet
- EnumSet
- List:有序可重复集合,可直接根据元素的索引来访问
- Map:存储key-value对的集合,可根据元素的key来访问value
- IdentityHashmap
- WeakHashMap
- HashMap-LinkedHashMap
- HashTable-Properties
- SortedMap-TreeMap
- EnumMap
2.线程安全和线程不安全
- 线程安全:Hashtable、ConcurrentHashMap、Vector(synchronized)、Stack
- 线程不安全:HashMap、ArrayList、LinkedList、HashSet、TreeSet、TreeMap
3.ArrayList与LinkedList
- 线程安全:不安全
- 底层数据结构
- ArrayList:Object数组
- LinkedList:双向循环链表
- 插入删除是否受位置影响
- ArrayList:数组存储,插入和删除元素的时间复杂度受元素位置影响,
- LinkedList:链表存储,插入和删除元素时间复杂度不受位置影响
- 是否支持快速随机访问
- ArrayList:实现了RandomAccess接口,能随机访问
- LinkedList:不支持高效的随机元素访问
- 内存空间占用
- ArrayList:在list列表的结尾会预留一定的容量空间
- LinkedList:每个元素都需要消耗比ArrayList更多的空间(要存放直接后继和直接前驱和数据)
4.ArrayList扩容机制
本质:计算出新的扩容数组size后实例化,并将原有数组内容复制到新数组去,默认情况下,新的容量会是原容量的1.5倍
5.Array和ArrayList
- Array可以包含基本类型和对象类型,ArrayList只能包含对象类型
- Array大小是固定的,ArrayList的大小是动态变化的
- ArrayList提供了更多的方法和特性,eg:addAll(),removeAll(),iterator()等
6.HashMap
- 底层数据结构
- 1.7 数组+链表,链表主要解决哈希冲突
- 1.8 数组+链表+红黑树,链表过长会严重影响HashMap的性能,红黑树搜索时间复杂度是O(logn),链表是O(n)。链表和红黑树的转换
- 当链表超过8且数据总量超过64才会转红黑树
- 将链表转换成红黑树前会判断,如果当前数组的长度小于64,会选择先进行数组扩容,而不是转换为红黑树,以减少搜索时间。
- 解决hash冲突
- 开放定址法(再散列法):以p为基础,再hash,以此类推,直到不冲突
- 再哈希法:提供多个hash函数,直到不冲突
- 链地址法:HashMap采用的方法。哈希值相同的元素构成一个单链表
- 建立公共溢出区:将哈希表分为公共表和溢出表,当溢出发生时,将所有溢出数据统一放到溢出区
- 加载因子
- Node[] table初始化长度为16,负载因子默认0.75,threshold是Hashmap所能容纳键值对的最大值,threshold=length*Load factor。在数组定义好长度之后,负载因子越大,所能容纳的键值对个数越多。
- 0.75是对空间和时间效率的一个平衡选择,一般不要修改,除非在时间和空间比较特殊的情况下
- 如果内存空间很多而又对时间效率要求很高,可以降低负载因子Load factor的值
- 如果内存空间紧张而对时间效率要求不高,可以增加负载因子loadFactory的值,这个值可以大于1
- key的存储索引怎么计算的
- 根据key的值计算出hashcode的值
- 根据hashcode计算出hash的值
- hash&(length-1)计算得到存储位置
- put流程
- 根据key计算出hash值,找到该元素再数组中存储的下标
- 如果数组是空的,调用resize进行初始化
- 如果没有哈希冲突直接放在对应的数组下标里
- 如果冲突,且key已经存在,覆盖掉value
- 如果冲突,发现该节点是红黑树,就将这个节点挂在树上
- 如果冲突后是链表,判断该链表是否大于8
- 如果大于8并且数组容量小于64,就扩容。
- 如果节点大于8并且数组容量大于64,结构转为红黑树,
- 否则,链表插入键值对,若key存在,就覆盖掉value
- 扩容
- 容量超过负载因子所定义的容量之后,就会扩容。将HashMap的大小扩大为原来数组的两倍,并将原来的对象放到新的数组中。
- 1.8两处优化
- resize之后,元素的位置在原来的位置或者原来位置+oldCap。如果bit是0,索引没变,如果是1则为原索引+oldcap
- 1.7中rehash的时候,旧链表迁移新链表的时候,如果在新表的数组索引位置相同,则链表元素会倒置(头插法),1.8不会倒置,使用尾插法。
- hashMap的key:一般用Integer,String这种不可变类当key,String最常用
- 因为字符串是不可变的,所以创建的时候hashcode就被缓存了,不需要重新计算
- 获取对象的时候要用到equals和hashcode,键对象正确的重写这两个方法是非常重要的。
- 为什么是线程不安全的
- 多线程下扩容死循环(1.7头插法导致的,1.8不会出现环形链表的问题)
- 多线程的put可能导致元素的丢失。如果计算出的索引位置相同,会造成前一个key被后一个key覆盖,从而导致元素丢失。
- put 和 get 并发时,可能导致get为null。线程1执行put,因为元素个数超出threshold导致rehash,线程2此时执行get,有可能导致这个问题。
7.ConcurrentHashMap
- 实现原理
- 1.7
- 由segment数组结构和HashEntry数组结构组成,把哈希桶切分成小数组,每个小数组有n个HashEntry组成。
- segment继承了ReentrantLock,所以segment是一种可重入锁,扮演锁的角色,HashEntry用于存储键值对数据
- 由segment数组结构和HashEntry数组结构组成,把哈希桶切分成小数组,每个小数组有n个HashEntry组成。
- 1.8
- 选择了与hashmap相同的数组+链表+红黑树结构。在锁的实现上,抛弃了原有的Segment分段锁,采用cas+synchronized实现更加低粒度的锁。将锁级别控制在了更细粒度的哈希桶元素级别,提高并发度
- 1.7
- put逻辑
- 1.7
- 尝试获取锁,获取失败,利用自旋获取锁,如果自旋重试次数超过64次,则改为阻塞获取锁
- 获取到锁后
- 将当前segment中的table通过key的hashcode定位到HashEntry
- 遍历该HashEntry,如果不为空则判断传入的key和当前遍历的key是否相等,相等则覆盖旧的value
- 不为空则需要新建一个HashEntry并加入到Segment中,同时会先判断是否需要扩容
- 释放segment的锁
- 1.8
- 根据key计算出hash的值
- 判断是否需要进行初始化
- 定位到Node,拿到首节点f,判断首节点f
- 如果为null,则通过cas的方式尝试添加
- 如果为f.hash=MOVED=-1,说明其他线程在扩容,参与一起扩容
- 如果都不满足,synchronized锁住f节点,判断是链表还是红黑树,遍历插入
- 当在链表长度达到8的时候数组扩容或者将链表转换为红黑树
- 1.7
- get方法不需要加锁
- Node的元素val和指针next是用volatile修饰的,在多线程环境下线程A修改节点的val或者新增节点的时候是对线程B可见的。
- 与volatile修饰的哈希桶没有关系:哈希桶主要是保证在数组扩容的时候保证可见性
- 不支持key或者value为null
- value不为null:无法判断是映射的value为null,还是没找到对应的key而为null。
- 并发度
- 1.7 默认16,可以在构造函数中设置,如果设置了并发度,ConcurrentHashMap会使用大于等于该值的最小的2的幂指数作为实际并发度,即如果设置的是17,则实际并发度为32
- 迭代器是强一致性还是弱一致性
- HashMap是强一致性,ConcurrentHashMap是弱一致性
- 迭代器创建后会按照哈希表结构遍历每个元素,在遍历过程中,内部元素可能发生变化,如果变化发生在已遍历过的部分,迭代器就不会反映出来,而如果变化发生在未遍历过的部分,迭代器会 发现并反映出来,即弱一致性。
8.Hashtable
- 使用Synchronized来实现线程安全,多线程访问的时候,只有一个线程能访问或操作对象。
9.多线程下安全的操作map还有其他方法么
- Collections.synchronizedMap:对方法进行加同步锁。如果传入的是HashMap对象,也是对HashMap做了一层包装,里面使用对象锁来保证多线程场景下线程安全,本质也是全表锁。
10.Collection框架中实现比较
- 内部比较器:实体类实现Comparable接口,并实现compareTo(T t)方法
- 外部比较器:实现Comparator接口的compare(T t1,T t2)
11.Iterator 和 ListIterator
- Iterator:遍历,可以遍历所有集合,eg:Map,List,Set,但只能再向前方向上遍历集合中的元素
- ListIterator:只能遍历List实现的对象,但可以向前和向后遍历集合中的元素
- 区别:
- 添加元素:Iterator无法向集合中添加元素,ListIterator可以向集合中添加元素
- 修改元素:Iterator无法修改元素,ListIterator可以使用set()修改集合中的元素
- 索引:Iterator无法获取集合中元素的索引,ListIterator可以获取结合中的索引
- 区别:
12.快速失败和安全失败
- 快速失败fail-fast
- 在用迭代器遍历一个集合对象时, 如果遍历过程中集合对象的内容进行了修改(增删改),则会抛出ConcurrentModificationException
- 原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个modCount变量,集合在被遍历期间如果内容发生变化,就会改变modCount的值,每当迭代器使用hashNext/next遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历,否则抛出异常,终止遍历。
- 注:这里异常的抛出条件是检测到modCount != expectedmodCount这个条件,如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出,因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug
- 场景:java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改),比如hashmap,arrayList这些集合类
- 安全失败fail-safe
- 采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历
- 原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发ConcurrentModification Exception
- 缺点:基于拷贝内容的优点避免了ConcurrentModificationException,但同样滴,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的
- 场景:java.util.concurrent包下的容器都是安全失败的,可以在多线程下并发使用,并发修改,比如ConcurrentHashMap
相关文章:
java集合总结
1.常见集合 Collection List:有序可重复集合,可直接根据元素的索引来访问 Vector-StackArrayListLinkedList Queue:队列集合 Deque-LinkedList、ArrayDequePriorityQueue Set:无序不可重复集合,只能根据元素本身来访问…...
list交并补差集合
list交并补差集合 工具类依赖 <dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.8.1</version> </dependency><dependency><groupId>commons-collections&…...
【微信小程序】父组件修改子组件数据或调用子组件方法
一、使用场景 页面中用到了自定义组件形成父子组件关系,在父组件某个特定时期想要操作子组件中的数据或方法,比如离开页面的时候清空子组件的数据。 二、方法 父组件可以通过this.selectComponent方法获取子组件实例对象,这样就可以直接访…...
frp通过nginx映射multipart/x-mixed-replace; boundary=frame流媒体出外网访问
要通过Nginx访问multipart/x-mixed-replace流媒体协议,并通过FRP进行映射访问,你可以按照以下步骤进行操作: 配置Nginx以支持multipart/x-mixed-replace流媒体协议。你需要编辑Nginx的配置文件(通常是nginx.conf)&…...
Kubernetes概述
Kubernetes概述 使用kubeadm快速部署一个k8s集群 Kubernetes高可用集群二进制部署(一)主机准备和负载均衡器安装 Kubernetes高可用集群二进制部署(二)ETCD集群部署 Kubernetes高可用集群二进制部署(三)部署…...
Jmeter教程
目录 安装与配置 一:下载jdk——配置jdk环境变量 二:下载JMeter——配置环境变量 安装与配置 一:下载jdk——配置jdk环境变量 1.新建环境变量变量名:JAVA_HOME变量值:(即JDK的安装路径) 2.编辑Path%J…...
用Rust实现23种设计模式之建造者模式
当使用 Rust 实现建造者模式时,我们可以通过结构体和方法链来实现。建造者模式是一种创建型设计模式,它允许你按照特定的顺序构建复杂对象,同时使你能够灵活地构建不同的变体。下面是一个使用 Rust 实现建造者模式的示例, 在示例中…...
聚观早报 | 腾讯字节等企业驰援防汛救灾;新能源车7月销量单出炉
【聚观365】8月4日消息 腾讯字节等企业驰援防汛救灾新能源车7月销量成绩单出炉Model Y等车型低温续航衰减严重华为Mate60系列猜想图曝光支付宝做短视频引来羊毛党 腾讯字节等企业驰援防汛救灾 近日,京津冀地区遭遇极端降雨天气,引发洪涝和地质灾害&…...
Crack:CAD Exchanger SDK 3.20 Web Toolkit 应用
在CAD Exchanger SDK 版本 3.20.0中,我们在 Web Toolkit 中包含了绘图、BIM 和 MCAD 查看器的示例,以展示如何使用每个工具可视化数据。这些查看器具有显示不同类型数据的特定功能,允许用户根据自己的需求单独使用它们。我们将继续增强每个查…...
改造 ChatGPT-Next-Web 项目重新生成 Docker 镜像
改造 ChatGPT-Next-Web 项目重新生成 Docker 镜像 0.背景1. 修改代码2. 生成 Docker 镜像3. 上传 Docker 镜像4. 运行 Docker 镜像 0.背景 需要通过 ChatGPT-Next-Web 使用自己搭建的 OpenAI API 兼容的服务器,需要对 ChatGPT-Next-Web 项目的少量代码进行改造。 …...
git修改commit日志
由于公司对版本提交日志进行检查,如果不符合要求,则push失败。 以下是修改commit日志的方法: 1.进入到提交代码文件所在目录,即git所在目录下 cd app-repository 2.git log git log commit bf29e3e5e799d364fe2975677baf18c9…...
Qt之qml和widget混合编程调用
首先是创建一个widget项目 然后需要添加qml和quick的插件使用 QT quickwidgets qml 接着要在界面上创建一个quickwidget和按钮 创建一个c对象类 QObjectQml #ifndef QOBJECTQML_H #define QOBJECTQML_H#include <QObject> #include <QDebug> class QObjectQml …...
深度学习torch基础知识
torch. detach()拼接函数torch.stack()torch.nn.DataParallel()np.clip()torch.linspace()PyTorch中tensor.repeat()pytorch索引查找 index_select detach() detach是截断反向传播的梯度流 将某个node变成不需要梯度的Varibale。因此当反向传播经过这个node时,梯度…...
【JAVA】正则表达式是啥?
个人主页:【😊个人主页】 系列专栏:【❤️初识JAVA】 文章目录 前言正则表达式正则表达式语法正则表达式的特点捕获组实例 前言 如果我们想要判断给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”),…...
网络安全之原型链污染
目录: 目录: 一、概念 二、举例 三、 实操了解 总结 四、抛出原题,历年原题复现 第一题: 五、分析与原理 第二题: 八、分析与原理 九、具体操作,payload与结果 结果: 一、概念 Java…...
【腾讯云Cloud Studio实战训练营】使用Cloud Studio迅捷开发一个3D家具个性化定制应用
目录 前言: 一、腾讯云 Cloud Studio介绍: 1、接近本地 IDE 的开发体验 2、多环境可选,或连接到云主机 3、随时分享预览效果 4、兼容 VSCode 插件 5、 AI代码助手 二、腾讯云Cloud Studio项目实践(3D家具个性化定制应用&…...
【计算机网络】第四章 网络层(一)
文章目录 第四章 网络层4.1 网络层概述4.2 网络层提供的两种服务4.2.1 小结 第四章 网络层 网络层是计算机网络体系结构中的一个关键层,位于传输层上方、数据链路层下方。它负责将传输层提供的数据分割成适当大小的数据包,并在不同网络之间进行路由选择和…...
Elasticsearch删除文档
根据id删除 例如删除id为110的文档 DELETE /ffbf/_doc/110返回信息 {"_index" : "ffbf","_type" : "_doc","_id" : "110","_version"...
MySQL数据库如何实现AX规范
本文我们来讨论 MySQL 的 XA 规范有哪些应用相关的内容。 MySQL 为我们提供了分布式事务解决方案,在前面的内容中 聊一聊分布式事务的解决方案 提到过 binlog 的同步,其实是 MySQL XA 规范的一个应用,那么 XA 规范是如何定义的,具…...
mac安装nvm
如果安装过node,须得卸载 sudo npm uninstall npm -gsudo rm -rf /usr/local/lib/node /usr/local/lib/node_modules /var/db/receipts/org.nodejs.*sudo rm -rf /usr/local/include/node /Users/$USER/.npmsudo rm /usr/local/bin/nodesudo rm /usr/local/share/m…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...
Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...
Python环境安装与虚拟环境配置详解
本文档旨在为Python开发者提供一站式的环境安装与虚拟环境配置指南,适用于Windows、macOS和Linux系统。无论你是初学者还是有经验的开发者,都能在此找到适合自己的环境搭建方法和常见问题的解决方案。 快速开始 一分钟快速安装与虚拟环境配置 # macOS/…...
