Java 课堂笔记:并发集合与内存可见性
一、ConcurrentHashMap 的细粒度锁机制
1.1 JDK 1.8 后的实现原理
· 放弃分段锁:改用 synchronized + CAS 操作
· 数据结构:数组 + 链表 + 红黑树
· 锁粒度:只锁住单个桶(bucket)的头节点
```java
// 核心方法 putVal 简化逻辑
final V putVal(K key, V value, boolean onlyIfAbsent) {
int hash = spread(key.hashCode());
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
tab = initTable(); // 无锁初始化
if ((p = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null, new Node<>(hash, key, value)))
break; // CAS 插入成功
} else {
synchronized (p) { // 仅锁当前桶
// 链表或红黑树插入
}
}
}
```
1.2 与 Hashtable 对比
特性 Hashtable ConcurrentHashMap
锁机制 全表锁 (synchronized method) 桶级锁
并发读 阻塞 无锁 (volatile 读)
迭代器 fail-fast weakly consistent
---
二、CopyOnWriteArrayList 写时复制
2.1 适用场景
· 读多写极少:如黑名单、配置列表
· 迭代操作远多于修改
2.2 实现要点
```java
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements); // 替换引用
return true;
} finally {
lock.unlock();
}
}
```
代价:每次修改都复制整个数组,内存开销大
---
三、内存可见性三要素
3.1 volatile 的 happens-before 规则
· 写 volatile → 读 volatile 建立 happens-before
· 不保证原子性(count++ 非原子)
3.2 错误示例与修正
```java
// ❌ 可能死循环(看不到修改)
class StopThread {
private static boolean stop;
public static void main(String[] args) throws Exception {
new Thread(() -> {
while (!stop) {} // 可能永远运行
}).start();
Thread.sleep(1000);
stop = true;
}
}
// ✅ 正确方式
private static volatile boolean stop;
```
3.3 synchronized 的可见性保证
· 线程释放锁前,强制将本地内存刷新到主内存
· 线程获取锁时,重新加载主内存数据
---
四、抽象队列同步器(AQS)基础
4.1 核心设计
· state:volatile int 状态标志
· CLH 队列:FIFO 双向链表管理等待线程
4.2 独占锁获取流程
```java
// tryAcquire 需子类实现
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
```
关键点:tryAcquire 需 CAS 修改 state
---
五、实战陷阱:ConcurrentHashMap 复合操作
```java
// ❌ 非原子操作
if (!map.containsKey(key)) {
map.put(key, value); // 两次操作间可能被其他线程插入
}
// ✅ 原子替代
map.putIfAbsent(key, value);
// ❌ 错误删除
map.remove(key);
// ✅ 条件删除
map.remove(key, expectedValue);
```
更多推荐




所有评论(0)