当前位置: 首页 > ai >正文

java集合面试

1. ​HashMap的实现原理是什么?JDK 1.8中如何解决哈希冲突?与JDK 1.7的主要区别是什么?

hashMap 实现原理:jdk1.7 之前是 数组和链表实现,jdk1.8 之后是数组和链表或者红黑树实现。
哈希冲突意思就是当要插入一对key-value 键值时候 对key做 hashcode 计算出来的数组索引和现在的数组发生了冲突;
jdk1.8 中如何解决哈希冲突:主要是用了链地址法,在对于一个 hashcode相同但是 equals 不一样的数据时候,hashmap 会将这个值利用尾插法插入到 hashmap 对应位置的链表尾部,当在数据插入时候hashmap还会去判断当前数组长度是否超过了设置的阈值(默认0.75*当前数组长度),以及判断是否需要将这个数组对应的链表转为红黑树,当数组超出64且当前链表长度超过8时候会触发转为红黑树的操作,转为红黑树后对于在这个链表上操作的时间复杂度会由原来的o(n)降到0(logn).但是对于以及转化为红黑树的链表如果长度小于6之后,也会触发由红黑树转变为链表的机制。
jdk1.7 中对于 hashcode相同但是 equals 不一样的数据 会将数据利用头插法插入链表。在jdk1.7 时候对于多线程情况下 hashmap插入之后,再去遍历时候可能会造成死循环。因为在jdk1.7中对于数据插入时候发生数组的扩容时候会造成链表的反转,导致死循环。
jdk1.8 改为了尾插法避免了这个问题但是如果在多线程的场景下建议使用 concurrentHashMap。

2. ​ConcurrentHashMap如何保证线程安全?在JDK 1.7和1.8中的实现有什么本质区别?

concurrentHashMap jdk1.7 中是对 segment 数组加锁,采用 reentrantLock 去实现加锁。jdk1.8中采用对node节点加锁,细化了加锁的颗粒度,增加了并发度。采用synchronized和cas 实现,当对于没有发生hashcode冲突时候通过无锁操作。只有在发生hashcode冲突时候才会去通过synchronized 去加锁完成,提高了效率。
AI 回答: JDK1.7 vs JDK1.8的ConcurrentHashMap实现

  1. ​JDK1.7(分段锁)​
    • 数据结构:Segment数组 + HashEntry链表
    • 锁机制:每个Segment独立ReentrantLock,锁住整个分段(多个桶)
    • 并发度:由Segment数量决定(默认16)
  2. ​JDK1.8(桶锁+CAS)
    • 数据结构:Node数组 + 链表/红黑树(同HashMap)
    • 锁机制:
      • 使用synchronized锁定单个桶的头节点(链表)或根节点(树)
      • CAS无锁化操作:插入、替换、初始化等场景优先使用CAS
    • 并发度:理论最大值等于桶数量(可动态扩容)
    • 扩容优化:多线程协作扩容(线程协助迁移数据)

3. ​ArrayList和LinkedList的区别是什么?在随机访问和增删操作的场景下如何选择?

ArrayList 底层是 泛型数组实现,具有扩容机制,当为空参构造函数创建时候,会默认为空数组,当插入第一个数据时候会进行扩容
变为10,对于已经满了,size> capacity 需要扩容时候会变为原来大小的1.5倍。对于空间使用必须是连续的。
LinkedList 是通过双向链表实现,不需要扩容,对于空间利用可以是不连续的。而且对于存储需要额外的空间去存储对于的前后指针。
在随机访问和增删操作的场景下如何选择:随机访问情况下选择ArrayList,ArrayList 有随机访问的功能,可以直接通过下标获取对应的value值,时间复杂度为o(1),而且对于ArrayList空间是连续的,会存在系统的页缓存情况,可能会更快。对于LinkedList来说时间复杂度需要o(n).
增删操作下:
对于尾部插入时候不考虑扩容机制,选择ArrayList,对于头部插入选择LinkedList 复杂度为o(1),ArrayList 需要对于后面的数据需要遍历挪位消耗过大。对于中间插入选择两个都可以,LinkedList虽然插入时候为o(1),但是对找到插入地址复杂度也是o(n),但是推荐ArrayList 对于空间连续操作时间会更快
对于删除时候和新增一样,尾部删除选择ArrayList;头部删除选择LinkedList;中间删除两者都可,但是推荐ArrayList 对于空间连续操作时间会更快

4. 什么是Fail-Fast机制?Iterator遍历集合时如何避免ConcurrentModificationException?

Fail-Fast机制是Java集合框架中的一种错误检测机制。当多个线程或同一线程在遍历集合的过程中直接修改集合的结构(如添加、删除元素),而未通过迭代器自身的修改方法时,会立即抛出ConcurrentModificationException,而不是继续执行潜在的错误操作。其核心实现依赖于集合内部的modCount(修改计数器):
创建迭代器时,迭代器会记录当前的modCount为expectedModCount。
每次迭代操作(如next()或remove())都会检查modCount与expectedModCount是否一致。若不一致,则抛出异常。

避免ConcurrentModificationException的方法:
​1、使用迭代器自身的修改方法:
2、​遍历后处理修改:
3、使用removeIf()方法(Java 8+)​

5. ​为什么说HashSet底层是基于HashMap实现的?TreeSet和LinkedHashSet在实现上有哪些核心差异?

6. Java中 reentrantlock

Java中 reentrantlock 是通过 aqs 机制和双向队列以及cas 实现,其中 reentrantlock 支持公平和非公平锁 也支持可重入通过state字段来记录持有锁次数,直到state字段为0时候才会去释放当前锁;reentrantlock 是需要手工来加锁以及释放。为非公平锁时候 是直接去通过cas去尝试加锁,加锁失败则进入到队列中等待;公平锁时候会先去判断线程中是否存在其他线程等待,如果没有才会去尝试加锁 如果有会加入到等待队列中;

AI回答:
Java 中的 ReentrantLock 是基于 AQS(AbstractQueuedSynchronizer)实现的独占锁,通过 volatile state 字段记录锁的重入次数,利用 CLH 双向队列管理等待线程,并通过 CAS 保证原子操作。它支持公平锁和非公平锁:

​非公平锁:线程首次加锁时直接尝试 CAS 修改 state,成功则获取锁,失败后进入队列等待。释放锁时唤醒队列头节点,但新线程仍可能插队(可能导致饥饿)。
​公平锁:加锁前会先检查队列是否有等待线程(hasQueuedPredecessors()),确保先到先得。
锁的重入性通过 state 自增实现,释放时递减到 0 才会完全释放。需要手动在 finally 块中调用 unlock() 避免死锁。此外,它还支持通过 Condition 实现精准的线程等待/唤醒机制,比 synchronized 更灵活。

7. threadlocal

8. 线程池

http://www.xdnf.cn/news/9284.html

相关文章:

  • 大语言模型 21 - MCP 自动操作 Figma+Cursor 实现自动原型开发!
  • 2025年该如何备考交安C证呢?
  • 多模态大语言模型arxiv论文略读(九十五)
  • PHP中的语句
  • Linux `pwd` 命令深度解析与高阶应用指南
  • mysql存储过程中rollback、transaction、动态sql的使用
  • 本地服务器搭建的git如何让外网访问?配置公网地址实现远程连接私有仓库
  • 解决el-input输入框输入数组传参报错
  • HarmonyOS NEXT~鸿蒙系统运维:全面解析与最佳实践
  • 鸿蒙OSUniApp 制作倒计时与提醒功能#三方框架 #Uniapp
  • 判断手机屏幕上的横向滑动(左滑和右滑)
  • 智慧康养护理:科技重塑老龄化社会的健康守护体系
  • 攻防世界逆向刷题笔记(新手模式9-1?)
  • (1)课堂 1--5,这五节主要讲解 mysql 的概念,定义,下载安装与卸载
  • LiveData的优势
  • Oracle EBS 12.1 处理ISG 发布的wsdl 被请求时遇到500错误
  • Docker常用操作
  • 无人机多人协同控制技术解析
  • linux ls命令显示目录颜色调整
  • ntp 时钟同步
  • 无人机停机坪运行技术分析!
  • OpenGL Chan视频学习-10 Dealing with Errors in OpenGL
  • c++数据结构4——链表结构详解
  • 【DSP笔记】掌握数字世界的律动:时域离散信号与系统基础
  • React - 封装礼物PK条组件
  • winform LiveCharts2的使用--图表的使用
  • 小土堆pytorch--现有网络模型的使用及修改
  • 数据结构中无向图的邻接矩阵详解
  • 鸿蒙OSUniApp 实现的数据可视化图表组件#三方框架 #Uniapp
  • Rust 学习笔记:迭代器