## JAVA面试题（1）

### [说说 Java 中 HashMap 的原理？](https://www.mianshiya.com/bank/1860871861809897474/question/1834107117591187457)

![image-20250402170337830](https://pic.bitday.top/i/2025/04/02/s66t0w-0.png)

**为什么引入红黑树:**
当hash冲突较多的时候，链表中的元素会增多，插入、删除、查询的效率会变低，退化成O(n)使用红黑树可以优化插入、删除、查询的效率，logN级别。

转换时机:
链表上的元素个数大于等于8 且 数组长度大于等于64；
链表上的元素个数小于等于6的时候，红黑树退化成链表。



**链表插入方式变更：从"头插法"改为"尾插法"**

- **头插法特点**：
  - 插入时不需要遍历链表
  - 直接替换头结点
  - 扩容时会导致链表逆序
  - 多线程环境下可能产生**死循环**
  
- **尾插法改进**：
  - 避免扩容时的链表逆序
  - 解决多线程环境下的潜在死循环问题



### [Java 中 ConcurrentHashMap 1.7 和 1.8 之间有哪些区别？](https://www.mianshiya.com/bank/1860871861809897474/question/1780933294813114369)

![image-20250402170530218](https://pic.bitday.top/i/2025/04/02/s7ahq2-0.png)

![image-20250402170553033](https://pic.bitday.top/i/2025/04/02/s7f94s-0.png)

#### ConcurrentHashMap 不同JDK版本的实现对比

1. **数据结构**

- JDK1.7：
  - 使用 `Segment（分段锁） + HashEntry数组 + 链表` 的数据结构

- JDK1.8及之后：
  - 使用 `数组 + 链表/红黑树` 的数据结构（与HashMap类似）

2. **锁的类型与宽度**

- JDK1.7：
  - 分段锁(Segment)继承了 `ReentrantLock`
  - Segment容量默认16，不会扩容 → 默认支持16个线程并发访问

- JDK1.8：
  - 使用 `synchronized + CAS` 保证线程安全
  - 空节点：通过CAS添加（**put操作**，多个线程可能同时想要将一个新的键值对插入到同一个桶中，这时它们会使用 CAS 来比较当前桶中的元素（或节点）是否已经被修改过。）
  - 非空节点：通过synchronized加锁，**只锁住该桶**，其他桶可以并行访问。

3. **渐进式扩容（JDK1.8+）**

- **触发条件**：元素数量 ≥ `数组容量 × 负载因子(默认0.75)`
- **扩容过程**：
  1. 创建2倍大小的新数组
  2. 线程操作数据时，逐步迁移旧数组数据到新数组
  3. 使用 `transferIndex` 标记迁移进度
  4. 直到旧数组数据完全迁移完成



### [500. 什么是 Java 的 CAS（Compare-And-Swap）操作？](https://www.mianshiya.com/question/1780933295027023873)

CAS操作包含三个基本操作数：

1. **内存位置(V)**：要更新的变量
2. **预期原值(A)**：认为变量当前应该具有的值
3. **新值(B)**：想要更新为的值

CAS 工作原理：

1. 读取内存位置V的当前值为A
2. 计算新值B
3. 当且仅当V的值等于A时，将V的值设置为B
4. 如果不等于A，则操作失败(通常重试)

```text
伪代码表示：
if (V == A) {
    V = B;
    return true;
} else {
    return false;
}
```

