锁体系详解
一、知识概述
Java并发包(java.util.concurrent.locks)提供了丰富的锁实现,相比synchronized关键字,这些锁提供了更灵活的功能,如可中断锁、公平锁、读写分离等。理解这些锁的原理和使用场景对于编写高性能并发程序至关重要。
锁体系概览
┌─────────────────────────────────────────────────────────────────────┐
│ Java锁体系架构 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Lock接口 │ │
│ │ void lock() 获取锁 │ │
│ │ void lockInterruptibly() 可中断获取锁 │ │
│ │ boolean tryLock() 尝试获取锁(立即返回) │ │
│ │ boolean tryLock(time) 超时尝试获取锁 │ │
│ │ void unlock() 释放锁 │ │
│ │ Condition newCondition() 创建条件变量 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │ ReentrantLock │ │ ReentrantRW │ │ StampedLock │ │
│ │ 可重入锁 │ │ 读写锁 │ │ 乐观读锁 │ │
│ └───────────────┘ └───────────────┘ └───────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 其他锁实现 │ │
│ ├─────────────────────────────────────────────────────────────┤ │
│ │ Semaphore 信号量(控制并发数) │ │
│ │ CountDownLatch 闭锁(一次性门闩) │ │
│ │ CyclicBarrier 循环栅栏 │ │
│ │ Phaser 阶段同步器 │ │
│ │ Exchanger 线程间数据交换 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
Lock vs synchronized
| 特性 | synchronized | Lock |
|---|---|---|
| 获取方式 | 隐式获取 | 显式调用lock() |
| 释放方式 | 自动释放 | 手动unlock() |
| 公平性 | 非公平 | 可选公平/非公平 |
| 中断 | 不支持 | 支持lockInterruptibly |
| 超时 | 不支持 | 支持tryLock(timeout) |
| 条件变量 | 单一条件 | 多条件变量 |
| 读写分离 | 不支持 | 支持 |
二、知识点详细讲解
2.1 ReentrantLock
2.1.1 基本使用
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
/**
* ReentrantLock基本使用
*/
public class ReentrantLockDemo {
public static void main(String[] args) {
System.out.println("=== ReentrantLock基本使用 ===\n");
basicUsage();
fairVsNonFair();
lockInterruptiblyDemo();
tryLockDemo();
}
/**
* 基本用法
*/
private static void basicUsage() {
System.out.println("【基本用法】\n");
class Counter {
private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock(); // 获取锁
try {
count++;
// 可以在此进行更多操作
} finally {
lock.unlock(); // 必须在finally中释放锁
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
}
Counter counter = new Counter();
// 多线程测试
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
counter.increment();
}
});
}
for (Thread t : threads) t.start();
for (Thread t : threads) {
try {
t.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.println("计数结果: " + counter.getCount());
System.out.println();
System.out.println("使用规范:");
System.out.println(" 1. lock()必须在try块之前或try块内调用");
System.out.println(" 2. unlock()必须在finally块中调用");
System.out.println(" 3. 确保锁一定会被释放");
System.out.println();
System.out.println("标准模式:");
System.out.println(" lock.lock();");
System.out.println(" try {");
System.out.println(" // 临界区代码");
System.out.println(" } finally {");
System.out.println(" lock.unlock();");
System.out.println(" }");
System.out.println();
}
/**
* 公平锁与非公平锁
*/
private static void fairVsNonFair() {
System.out.println("【公平锁 vs 非公平锁】\n");
System.out.println("创建方式:");
System.out.println(" ReentrantLock lock = new ReentrantLock(); // 非公平锁(默认)");
System.out.println(" ReentrantLock lock = new ReentrantLock(true); // 公平锁");
System.out.println();
System.out.println("公平锁:");
System.out.println(" - 按等待顺序获取锁");
System.out.println(" - 避免线程饥饿");
System.out.println(" - 性能较低(需要维护队列)");
System.out.println();
System.out.println("非公平锁:");
System.out.println(" - 不保证顺序");
System.out.println(" - 可能导致线程饥饿");
System.out.println(" - 性能较高(减少线程切换)");
System.out.println();
System.out.println("选择建议:");
System.out.println(" - 大多数场景使用非公平锁(默认)");
System.out.println(" - 需要严格公平性时使用公平锁");
System.out.println();
}
/**
* 可中断锁
*/
private static void lockInterruptiblyDemo() {
System.out.println("【可中断锁】\n");
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
try {
System.out.println("线程1尝试获取锁...");
lock.lockInterruptibly(); // 可中断获取锁
try {
System.out.println("线程1获取锁成功");
Thread.sleep(10000); // 持有锁10秒
} finally {
lock.unlock();
System.out.println("线程1释放锁");
}
} catch (InterruptedException e) {
System.out.println("线程1被中断,放弃获取锁");
Thread.currentThread().interrupt();
}
});
Thread t2 = new Thread(() -> {
try {
Thread.sleep(100); // 确保t1先获取锁
System.out.println("线程2尝试获取锁...");
lock.lockInterruptibly();
try {
System.out.println("线程2获取锁成功");
} finally {
lock.unlock();
}
} catch (InterruptedException e) {
System.out.println("线程2被中断,放弃获取锁");
Thread.currentThread().interrupt();
}
});
t1.start();
t2.start();
try {
Thread.sleep(1000);
System.out.println("主线程中断线程2");
t2.interrupt(); // 中断等待获取锁的线程
t1.join();
t2.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println();
System.out.println("说明:");
System.out.println(" - lockInterruptibly()可以响应中断");
System.out.println(" - synchronized无法被中断");
System.out.println(" - 适用于需要取消等待锁的场景");
System.out.println();
}
/**
* 尝试获取锁
*/
private static void tryLockDemo() throws InterruptedException {
System.out.println("【tryLock尝试获取锁】\n");
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
if (lock.tryLock()) { // 立即返回
try {
System.out.println("线程1获取锁成功");
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
} else {
System.out.println("线程1获取锁失败,执行其他逻辑");
}
});
Thread t2 = new Thread(() -> {
try {
// 超时获取锁
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try {
System.out.println("线程2获取锁成功");
} finally {
lock.unlock();
}
} else {
System.out.println("线程2获取锁超时,执行其他逻辑");
}
} catch (InterruptedException e) {
System.out.println("线程2被中断");
Thread.currentThread().interrupt();
}
});
t1.start();
Thread.sleep(100); // 确保t1先获取锁
t2.start();
t1.join();
t2.join();
System.out.println();
System.out.println("tryLock变体:");
System.out.println(" tryLock(): 立即返回,成功返回true");
System.out.println(" tryLock(time, unit): 超时等待,可中断");
System.out.println();
System.out.println("应用场景:");
System.out.println(" - 避免死锁(获取不到锁时执行其他逻辑)");
System.out.println(" - 限时等待");
System.out.println(" - 多锁获取(尝试获取多个锁,失败则释放已获取的锁)");
System.out.println();
}
}
2.1.2 ReentrantLock高级特性
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
/**
* ReentrantLock高级特性
*/
public class ReentrantLockAdvancedDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== ReentrantLock高级特性 ===\n");
reentrantDemo();
conditionDemo();
lockStateDemo();
}
/**
* 可重入性演示
*/
private static void reentrantDemo() {
System.out.println("【可重入性】\n");
class ReentrantExample {
private final ReentrantLock lock = new ReentrantLock();
public void methodA() {
lock.lock();
try {
System.out.println("methodA获取锁,持有次数: " + lock.getHoldCount());
methodB(); // 重入
System.out.println("methodA执行完毕");
} finally {
lock.unlock();
}
}
public void methodB() {
lock.lock();
try {
System.out.println("methodB获取锁,持有次数: " + lock.getHoldCount());
methodC();
System.out.println("methodB执行完毕");
} finally {
lock.unlock();
}
}
public void methodC() {
lock.lock();
try {
System.out.println("methodC获取锁,持有次数: " + lock.getHoldCount());
} finally {
lock.unlock();
}
}
}
new ReentrantExample().methodA();
System.out.println();
System.out.println("说明:");
System.out.println(" - 同一线程可多次获取同一把锁");
System.out.println(" - 每次lock()计数器+1");
System.out.println(" - 每次unlock()计数器-1");
System.out.println(" - 计数器为0时真正释放锁");
System.out.println();
}
/**
* Condition条件变量
*/
private static void conditionDemo() throws InterruptedException {
System.out.println("【Condition条件变量】\n");
class BoundedBuffer<T> {
private final Object[] items;
private int putIndex, takeIndex, count;
private final ReentrantLock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition(); // 非满条件
private final Condition notEmpty = lock.newCondition(); // 非空条件
public BoundedBuffer(int capacity) {
items = new Object[capacity];
}
@SuppressWarnings("unchecked")
public T take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
notEmpty.await(); // 等待非空
}
Object item = items[takeIndex];
items[takeIndex] = null;
takeIndex = (takeIndex + 1) % items.length;
count--;
notFull.signal(); // 通知非满
return (T) item;
} finally {
lock.unlock();
}
}
public void put(T item) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
notFull.await(); // 等待非满
}
items[putIndex] = item;
putIndex = (putIndex + 1) % items.length;
count++;
notEmpty.signal(); // 通知非空
} finally {
lock.unlock();
}
}
}
BoundedBuffer<String> buffer = new BoundedBuffer<>(3);
// 生产者
Thread producer = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
buffer.put("Item-" + i);
System.out.println("生产: Item-" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
// 消费者
Thread consumer = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
String item = buffer.take();
System.out.println("消费: " + item);
Thread.sleep(200);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
producer.start();
consumer.start();
producer.join();
consumer.join();
System.out.println();
System.out.println("Condition方法:");
System.out.println(" await(): 等待,释放锁");
System.out.println(" awaitUninterruptibly(): 不可中断等待");
System.out.println(" await(time, unit): 超时等待");
System.out.println(" signal(): 唤醒一个等待线程");
System.out.println(" signalAll(): 唤醒所有等待线程");
System.out.println();
System.out.println("优势:");
System.out.println(" - 一个Lock可以有多个Condition");
System.out.println(" - 可以精确控制唤醒哪些线程");
System.out.println(" - 比wait/notify更灵活");
System.out.println();
}
/**
* 锁状态查询
*/
private static void lockStateDemo() {
System.out.println("【锁状态查询】\n");
ReentrantLock lock = new ReentrantLock();
System.out.println("锁状态方法:");
System.out.println(" isLocked(): 是否被持有");
System.out.println(" isFair(): 是否公平锁");
System.out.println(" isHeldByCurrentThread(): 当前线程是否持有");
System.out.println(" getHoldCount(): 当前线程持有次数");
System.out.println(" getQueueLength(): 等待队列长度");
System.out.println(" hasQueuedThreads(): 是否有线程在等待");
System.out.println(" hasWaiters(condition): 是否有线程在condition上等待");
System.out.println(" getWaitQueueLength(condition): condition上等待的线程数");
System.out.println();
// 演示
System.out.println("初始状态:");
System.out.println(" isLocked: " + lock.isLocked());
System.out.println(" isFair: " + lock.isFair());
System.out.println();
lock.lock();
System.out.println("获取锁后:");
System.out.println(" isLocked: " + lock.isLocked());
System.out.println(" isHeldByCurrentThread: " + lock.isHeldByCurrentThread());
System.out.println(" getHoldCount: " + lock.getHoldCount());
lock.lock(); // 重入
System.out.println("再次获取锁:");
System.out.println(" getHoldCount: " + lock.getHoldCount());
lock.unlock();
lock.unlock();
System.out.println();
}
}
2.1.3 ReentrantLock原理
/**
* ReentrantLock实现原理
*/
public class ReentrantLockPrincipleDemo {
public static void main(String[] args) {
System.out.println("=== ReentrantLock实现原理 ===\n");
aqsDemo();
syncDemo();
}
/**
* AQS (AbstractQueuedSynchronizer)
*/
private static void aqsDemo() {
System.out.println("【AQS核心概念】\n");
/*
AQS是并发包中锁的基础框架
核心组成:
1. state变量 (volatile int state)
- 表示锁的状态
- ReentrantLock: state=0表示未锁定,>0表示被锁定(可重入次数)
- Semaphore: state表示剩余许可数
- CountDownLatch: state表示计数值
2. CLH队列 (双向链表)
- 存储等待获取锁的线程
- Node节点包含: thread, waitStatus, prev, next
3. CAS操作
- 修改state变量
- 入队/出队操作
*/
System.out.println("AQS结构:");
System.out.println("""
┌─────────────────────────────────────────────────────┐
│ AQS核心结构 │
├─────────────────────────────────────────────────────┤
│ │
│ volatile int state = 0; // 同步状态 │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ CLH等待队列 │ │
│ │ │ │
│ │ head ──► Node ──► Node ──► Node ◄── tail │ │
│ │ │ │ │ │ │
│ │ thread thread thread │ │
│ │ waitStatus waitStatus waitStatus │ │
│ └─────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────┘
""");
System.out.println("Node节点状态:");
System.out.println(" CANCELLED(1): 线程已取消");
System.out.println(" SIGNAL(-1): 后继线程需要唤醒");
System.out.println(" CONDITION(-2): 线程在条件队列等待");
System.out.println(" PROPAGATE(-3): 共享模式传播");
System.out.println(" 0: 初始状态");
System.out.println();
System.out.println("AQS模板方法:");
System.out.println(" tryAcquire(int): 独占式获取锁");
System.out.println(" tryRelease(int): 独占式释放锁");
System.out.println(" tryAcquireShared(int): 共享式获取锁");
System.out.println(" tryReleaseShared(int): 共享式释放锁");
System.out.println(" isHeldExclusively(): 是否被独占持有");
System.out.println();
}
/**
* 同步器实现
*/
private static void syncDemo() {
System.out.println("【ReentrantLock的Sync实现】\n");
/*
ReentrantLock内部类:
abstract static class Sync extends AbstractQueuedSynchronizer {
// 抽象方法,由子类实现
abstract void lock();
}
static final class NonfairSync extends Sync {
final void lock() {
// 非公平锁:先尝试CAS获取
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
}
static final class FairSync extends Sync {
final void lock() {
acquire(1); // 公平锁:直接进入队列
}
}
*/
System.out.println("非公平锁获取流程:");
System.out.println(" 1. CAS尝试将state从0改为1");
System.out.println(" 2. 成功: 设置当前线程为独占线程");
System.out.println(" 3. 失败: 调用acquire()进入队列");
System.out.println();
System.out.println("公平锁获取流程:");
System.out.println(" 1. 检查队列是否有前驱节点");
System.out.println(" 2. 无前驱: CAS获取锁");
System.out.println(" 3. 有前驱: 进入队列等待");
System.out.println();
System.out.println("acquire流程:");
System.out.println(" 1. tryAcquire(): 尝试获取锁");
System.out.println(" 2. addWaiter(): 加入队列尾部");
System.out.println(" 3. acquireQueued(): 自旋获取锁");
System.out.println(" 4. shouldParkAfterFailedAcquire(): 检查是否需要阻塞");
System.out.println(" 5. parkAndCheckInterrupt(): 阻塞线程");
System.out.println();
}
}
2.2 ReentrantReadWriteLock
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
/**
* ReentrantReadWriteLock读写锁
*/
public class ReentrantReadWriteLockDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== ReentrantReadWriteLock ===\n");
basicUsage();
lockDowngrading();
useCaseDemo();
}
/**
* 基本使用
*/
private static void basicUsage() {
System.out.println("【基本使用】\n");
class ReadWriteResource {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
private int value = 0;
public int read() {
readLock.lock(); // 获取读锁
try {
System.out.println(Thread.currentThread().getName() + " 读取: " + value);
return value;
} finally {
readLock.unlock();
}
}
public void write(int newValue) {
writeLock.lock(); // 获取写锁
try {
System.out.println(Thread.currentThread().getName() + " 写入: " + newValue);
value = newValue;
} finally {
writeLock.unlock();
}
}
}
ReadWriteResource resource = new ReadWriteResource();
// 多个读线程
Thread[] readers = new Thread[3];
for (int i = 0; i < 3; i++) {
readers[i] = new Thread(() -> {
for (int j = 0; j < 3; j++) {
resource.read();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}, "Reader-" + i);
}
// 写线程
Thread writer = new Thread(() -> {
for (int i = 0; i < 3; i++) {
resource.write(i * 10);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}, "Writer");
for (Thread t : readers) t.start();
writer.start();
for (Thread t : readers) {
try {
t.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
try {
writer.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println();
System.out.println("读写锁特性:");
System.out.println(" - 读锁: 共享锁,多个线程可同时持有");
System.out.println(" - 写锁: 独占锁,只有一个线程可持有");
System.out.println(" - 读读: 不互斥");
System.out.println(" - 读写: 互斥");
System.out.println(" - 写写: 互斥");
System.out.println();
}
/**
* 锁降级
*/
private static void lockDowngrading() {
System.out.println("【锁降级】\n");
class CacheWithDowngrade {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
private Object data;
private boolean valid = false;
public Object getData() {
readLock.lock();
try {
if (!valid) {
// 需要更新数据,释放读锁
readLock.unlock();
// 获取写锁
writeLock.lock();
try {
// 再次检查(可能其他线程已更新)
if (!valid) {
data = loadDataFromDB();
valid = true;
}
// 锁降级:获取读锁后再释放写锁
readLock.lock(); // 降级开始
} finally {
writeLock.unlock(); // 释放写锁,降级完成
}
// 现在只有读锁
}
return data;
} finally {
readLock.unlock();
}
}
private Object loadDataFromDB() {
return "Data from DB";
}
}
System.out.println("锁降级流程:");
System.out.println(" 1. 获取写锁");
System.out.println(" 2. 更新数据");
System.out.println(" 3. 获取读锁(在释放写锁之前)");
System.out.println(" 4. 释放写锁");
System.out.println(" 5. 现在只有读锁,其他线程可读取");
System.out.println();
System.out.println("⚠️ 注意:");
System.out.println(" - 锁升级(读锁→写锁)不被支持,会导致死锁");
System.out.println(" - 只能从写锁降级到读锁");
System.out.println();
}
/**
* 应用场景
*/
private static void useCaseDemo() {
System.out.println("【应用场景】\n");
System.out.println("适合场景:");
System.out.println(" 1. 读多写少的缓存");
System.out.println(" 2. 配置信息读取");
System.out.println(" 3. 资源元数据查询");
System.out.println();
System.out.println("示例: 线程安全的缓存");
System.out.println("""
class Cache<K, V> {
private final Map<K, V> map = new HashMap<>();
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
public V get(K key) {
rwLock.readLock().lock();
try {
return map.get(key);
} finally {
rwLock.readLock().unlock();
}
}
public void put(K key, V value) {
rwLock.writeLock().lock();
try {
map.put(key, value);
} finally {
rwLock.writeLock().unlock();
}
}
}
""");
System.out.println("注意事项:");
System.out.println(" - 写锁获取时会阻塞所有读锁");
System.out.println(" - 可能导致写线程饥饿");
System.out.println(" - 公平模式下可以避免");
System.out.println();
}
}
2.3 StampedLock
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
/**
* StampedLock乐观读锁
*/
public class StampedLockDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== StampedLock ===\n");
basicUsage();
optimisticRead();
performanceComparison();
}
/**
* 基本使用
*/
private static void basicUsage() {
System.out.println("【基本使用】\n");
class Point {
private final StampedLock sl = new StampedLock();
private double x, y;
// 写锁
public void move(double deltaX, double deltaY) {
long stamp = sl.writeLock(); // 获取写锁,返回戳记(stamp)
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp); // 释放写锁
}
}
// 悲观读锁
public double distanceFromOrigin() {
long stamp = sl.readLock(); // 获取读锁
try {
return Math.sqrt(x * x + y * y);
} finally {
sl.unlockRead(stamp); // 释放读锁
}
}
// 乐观读
public double distanceFromOriginOptimistic() {
long stamp = sl.tryOptimisticRead(); // 获取乐观读戳记
double currentX = x, currentY = y; // 读取数据
if (!sl.validate(stamp)) { // 验证戳记是否有效
stamp = sl.readLock(); // 失败则获取读锁
try {
currentX = x;
currentY = y;
} finally {
sl.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
}
Point point = new Point();
point.move(3, 4);
System.out.println("距离: " + point.distanceFromOrigin());
System.out.println("距离(乐观读): " + point.distanceFromOriginOptimistic());
System.out.println();
System.out.println("StampedLock特点:");
System.out.println(" - Java 8引入");
System.out.println(" - 性能优于ReentrantReadWriteLock");
System.out.println(" - 支持乐观读");
System.out.println(" - 不可重入!");
System.out.println(" - 不是ReentrantLock的子类");
System.out.println();
System.out.println("锁类型:");
System.out.println(" writeLock(): 写锁(独占)");
System.out.println(" readLock(): 读锁(共享)");
System.out.println(" tryOptimisticRead(): 乐观读(无锁)");
System.out.println();
}
/**
* 乐观读详解
*/
private static void optimisticRead() throws InterruptedException {
System.out.println("【乐观读详解】\n");
class OptimisticResource {
private final StampedLock sl = new StampedLock();
private int value = 0;
public void write(int newValue) {
long stamp = sl.writeLock();
try {
value = newValue;
System.out.println("写入: " + newValue);
} finally {
sl.unlockWrite(stamp);
}
}
public int read() {
// 乐观读 - 无锁
long stamp = sl.tryOptimisticRead();
int currentValue = value;
// 验证期间可能有写操作
if (!sl.validate(stamp)) {
System.out.println("乐观读失败,降级为悲观读");
// 降级为悲观读
stamp = sl.readLock();
try {
currentValue = value;
} finally {
sl.unlockRead(stamp);
}
} else {
System.out.println("乐观读成功: " + currentValue);
}
return currentValue;
}
// 乐观读 + 写锁转换
public int tryConvertToWrite() {
long stamp = sl.tryOptimisticRead();
int currentValue = value;
if (!sl.validate(stamp)) {
// 转换为写锁
stamp = sl.writeLock();
try {
currentValue = value;
value = currentValue + 1;
return value;
} finally {
sl.unlockWrite(stamp);
}
}
// 尝试直接转换为写锁
long ws = sl.tryConvertToWriteLock(stamp);
if (ws != 0) {
// 转换成功
value = currentValue + 1;
sl.unlockWrite(ws);
return value;
}
// 转换失败,释放并重新获取
sl.unlockRead(stamp);
return tryConvertToWrite();
}
}
OptimisticResource resource = new OptimisticResource();
Thread writer = new Thread(() -> {
for (int i = 0; i < 5; i++) {
resource.write(i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
Thread reader = new Thread(() -> {
for (int i = 0; i < 10; i++) {
resource.read();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
writer.start();
reader.start();
writer.join();
reader.join();
System.out.println();
System.out.println("乐观读原理:");
System.out.println(" 1. tryOptimisticRead(): 返回一个戳记(stamp)");
System.out.println(" 2. 读取共享变量(不加锁)");
System.out.println(" 3. validate(stamp): 检查戳记是否仍然有效");
System.out.println(" 4. 有效: 说明没有写操作,数据一致");
System.out.println(" 5. 无效: 有写操作发生,需要重新读取");
System.out.println();
System.out.println("适用场景:");
System.out.println(" - 读操作远多于写操作");
System.out.println(" - 对一致性要求不是特别严格");
System.out.println(" - 可以接受偶尔的重读");
System.out.println();
}
/**
* 性能对比
*/
private static void performanceComparison() throws InterruptedException {
System.out.println("【性能对比】\n");
int threadCount = 10;
int iterations = 100000;
// ReentrantLock
class ReentrantCounter {
private final ReentrantLock lock = new ReentrantLock();
private int value = 0;
public void increment() {
lock.lock();
try { value++; } finally { lock.unlock(); }
}
public int get() {
lock.lock();
try { return value; } finally { lock.unlock(); }
}
}
// ReentrantReadWriteLock
class RWCounter {
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private int value = 0;
public void increment() {
lock.writeLock().lock();
try { value++; } finally { lock.writeLock().unlock(); }
}
public int get() {
lock.readLock().lock();
try { return value; } finally { lock.readLock().unlock(); }
}
}
// StampedLock
class StampedCounter {
private final StampedLock lock = new StampedLock();
private int value = 0;
public void increment() {
long stamp = lock.writeLock();
try { value++; } finally { lock.unlockWrite(stamp); }
}
public int get() {
long stamp = lock.tryOptimisticRead();
int v = value;
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try { v = value; } finally { lock.unlockRead(stamp); }
}
return v;
}
}
// 测试
System.out.println("读多写少场景 (90%读, 10%写):");
// ReentrantLock
ReentrantCounter rc = new ReentrantCounter();
long start = System.currentTimeMillis();
Thread[] rt1 = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
rt1[i] = new Thread(() -> {
for (int j = 0; j < iterations; j++) {
if (j % 10 == 0) rc.increment();
else rc.get();
}
});
}
for (Thread t : rt1) t.start();
for (Thread t : rt1) t.join();
System.out.println("ReentrantLock: " + (System.currentTimeMillis() - start) + "ms");
// ReentrantReadWriteLock
RWCounter rwc = new RWCounter();
start = System.currentTimeMillis();
Thread[] rt2 = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
rt2[i] = new Thread(() -> {
for (int j = 0; j < iterations; j++) {
if (j % 10 == 0) rwc.increment();
else rwc.get();
}
});
}
for (Thread t : rt2) t.start();
for (Thread t : rt2) t.join();
System.out.println("ReentrantReadWriteLock: " + (System.currentTimeMillis() - start) + "ms");
// StampedLock
StampedCounter sc = new StampedCounter();
start = System.currentTimeMillis();
Thread[] rt3 = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
rt3[i] = new Thread(() -> {
for (int j = 0; j < iterations; j++) {
if (j % 10 == 0) sc.increment();
else sc.get();
}
});
}
for (Thread t : rt3) t.start();
for (Thread t : rt3) t.join();
System.out.println("StampedLock(乐观读): " + (System.currentTimeMillis() - start) + "ms");
System.out.println();
System.out.println("结论:");
System.out.println(" - 读多写少: StampedLock > ReentrantReadWriteLock > ReentrantLock");
System.out.println(" - 写多读少: ReentrantLock ≈ StampedLock ≈ ReentrantReadWriteLock");
System.out.println(" - StampedLock乐观读性能最优");
System.out.println();
}
}
三、可运行Java代码示例
完整示例:多锁协作
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
/**
* 多锁协作完整示例
*/
public class LockCoordinationDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== 多锁协作示例 ===\n");
// 死锁避免
deadlockAvoidance();
// 生产者-消费者
producerConsumerWithCondition();
}
/**
* 死锁避免
*/
private static void deadlockAvoidance() throws InterruptedException {
System.out.println("【死锁避免】\n");
class BankAccount {
private final Lock lock = new ReentrantLock();
private int balance;
public final int id;
public BankAccount(int id, int balance) {
this.id = id;
this.balance = balance;
}
public boolean tryLock() {
return lock.tryLock();
}
public void lock() {
lock.lock();
}
public void unlock() {
lock.unlock();
}
public void withdraw(int amount) {
balance -= amount;
}
public void deposit(int amount) {
balance += amount;
}
public int getBalance() {
return balance;
}
}
// 死锁示例(注释掉,因为会导致程序卡死)
/*
void transferDeadlock(BankAccount from, BankAccount to, int amount) {
synchronized (from) {
synchronized (to) {
from.withdraw(amount);
to.deposit(amount);
}
}
}
*/
// 正确方式1: 按顺序获取锁
class SafeTransfer1 {
public void transfer(BankAccount from, BankAccount to, int amount) {
BankAccount first = from.id < to.id ? from : to;
BankAccount second = from.id < to.id ? to : from;
first.lock();
try {
second.lock();
try {
from.withdraw(amount);
to.deposit(amount);
System.out.println("转账成功: " + amount);
} finally {
second.unlock();
}
} finally {
first.unlock();
}
}
}
// 正确方式2: tryLock避免死锁
class SafeTransfer2 {
public boolean transfer(BankAccount from, BankAccount to, int amount) {
while (true) {
if (from.tryLock()) {
try {
if (to.tryLock()) {
try {
from.withdraw(amount);
to.deposit(amount);
System.out.println("转账成功: " + amount);
return true;
} finally {
to.unlock();
}
}
} finally {
from.unlock();
}
}
// 两个锁都没获取到,稍后重试
try {
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
}
}
BankAccount account1 = new BankAccount(1, 1000);
BankAccount account2 = new BankAccount(2, 1000);
SafeTransfer1 transfer1 = new SafeTransfer1();
transfer1.transfer(account1, account2, 100);
System.out.println("账户1余额: " + account1.getBalance());
System.out.println("账户2余额: " + account2.getBalance());
System.out.println();
System.out.println("避免死锁的方法:");
System.out.println(" 1. 按固定顺序获取锁");
System.out.println(" 2. 使用tryLock()超时");
System.out.println(" 3. 使用Lock的tryLock()尝试获取");
System.out.println(" 4. 使用定时锁(带超时的tryLock)");
System.out.println();
}
/**
* 使用Condition实现生产者-消费者
*/
private static void producerConsumerWithCondition() throws InterruptedException {
System.out.println("【Condition实现生产者-消费者】\n");
class BoundedQueue<T> {
private final Object[] items;
private int putIndex, takeIndex, count;
private final ReentrantLock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
public BoundedQueue(int capacity) {
items = new Object[capacity];
}
public void put(T item) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
System.out.println("队列已满,生产者等待");
notFull.await();
}
items[putIndex] = item;
putIndex = (putIndex + 1) % items.length;
count++;
System.out.println("生产: " + item + ", 队列大小: " + count);
notEmpty.signal();
} finally {
lock.unlock();
}
}
@SuppressWarnings("unchecked")
public T take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
System.out.println("队列为空,消费者等待");
notEmpty.await();
}
Object item = items[takeIndex];
items[takeIndex] = null;
takeIndex = (takeIndex + 1) % items.length;
count--;
System.out.println("消费: " + item + ", 队列大小: " + count);
notFull.signal();
return (T) item;
} finally {
lock.unlock();
}
}
}
BoundedQueue<String> queue = new BoundedQueue<>(3);
Thread producer = new Thread(() -> {
String[] items = {"A", "B", "C", "D", "E"};
for (String item : items) {
try {
queue.put(item);
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
Thread consumer = new Thread(() -> {
for (int i = 0; i < 5; i++) {
try {
queue.take();
Thread.sleep(200);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
producer.start();
consumer.start();
producer.join();
consumer.join();
System.out.println();
}
}
四、总结与最佳实践
核心要点回顾
| 锁类型 | 特点 | 适用场景 |
|---|---|---|
| ReentrantLock | 可重入、可中断、公平/非公平 | 复杂同步、需要条件变量 |
| ReentrantReadWriteLock | 读写分离 | 读多写少 |
| StampedLock | 乐观读、高性能 | 读极多写极少 |
最佳实践
-
正确释放锁
lock.lock(); try { // 临界区代码 } finally { lock.unlock(); } -
避免死锁
- 按固定顺序获取多把锁
- 使用tryLock超时
- 尽量减少锁的持有时间
-
选择合适的锁
- 简单同步用synchronized
- 需要高级特性用ReentrantLock
- 读多写少用ReadWriteLock
- 极致读性能用StampedLock
-
注意StampedLock不可重入
- 不要在持有StampedLock时调用其他获取同一把锁的方法
扩展阅读
- 《Java并发编程实战》:锁章节
- 《Java并发编程的艺术》:AQS详解
- JDK源码:java.util.concurrent.locks包