13-Java语言核心-并发编程-锁体系详解

0 阅读14分钟

锁体系详解

一、知识概述

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

特性synchronizedLock
获取方式隐式获取显式调用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乐观读、高性能读极多写极少

最佳实践

  1. 正确释放锁

    lock.lock();
    try {
        // 临界区代码
    } finally {
        lock.unlock();
    }
    
  2. 避免死锁

    • 按固定顺序获取多把锁
    • 使用tryLock超时
    • 尽量减少锁的持有时间
  3. 选择合适的锁

    • 简单同步用synchronized
    • 需要高级特性用ReentrantLock
    • 读多写少用ReadWriteLock
    • 极致读性能用StampedLock
  4. 注意StampedLock不可重入

    • 不要在持有StampedLock时调用其他获取同一把锁的方法

扩展阅读

  • 《Java并发编程实战》:锁章节
  • 《Java并发编程的艺术》:AQS详解
  • JDK源码:java.util.concurrent.locks包