JDK 8 Semaphore 源码详解(详细注释版)

JDK 8 Semaphore 源码详解(详细注释版)

1. 类定义和基本属性

public class Semaphore implements java.io.Serializable {
    
    // 序列化版本号
    private static final long serialVersionUID = -322257861600715216L;

    /**
     * Semaphore的核心同步器
     * 继承自AbstractQueuedSynchronizer(AQS)
     * 通过AQS的state字段来表示可用的许可数量
     * 
     * 设计巧妙之处:
     * - 利用AQS的共享锁机制实现信号量
     * - state字段表示可用许可数
     * - 正数表示可用许可,0表示无可用许可
     * - 通过共享模式实现多个线程同时获取许可
     */
    private final Sync sync;

    /**
     * 同步器抽象基类
     * 继承自AbstractQueuedSynchronizer
     * 提供了信号量的基本功能
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 1192457210091910933L;

        /**
         * 构造方法
         * 初始化信号量的许可数量
         * @param permits 初始许可数量
         * 
         * 初始化过程:
         * 1. 调用AQS的setState方法设置state字段
         * 2. state字段表示可用的许可数量
         * 3. permits必须为非负数
         */
        Sync(int permits) {
            setState(permits);
        }

        /**
         * 获取当前可用的许可数量
         * @return 当前可用的许可数量
         * 
         * 获取过程:
         * 1. 调用AQS的getState方法获取state字段
         * 2. state字段表示可用的许可数量
         * 3. 返回当前可用许可数
         * 
         * 时间复杂度:O(1)
         * 线程安全性:完全线程安全
         */
        final int getPermits() {
            return getState();
        }

        /**
         * 非公平方式获取许可
         * 这是Semaphore的核心实现
         * @param acquires 要获取的许可数量
         * @return 如果获取成功返回true,否则返回false
         * 
         * 获取过程:
         * 1. 使用CAS操作尝试减少许可数量
         * 2. 如果成功,获取成功返回true
         * 3. 如果失败,说明许可不足,返回false
         * 
         * 非公平特点:
         * - 允许插队,不检查等待队列
         * - 性能更好,但可能导致线程饥饿
         */
        final boolean nonfairTryAcquireShared(int acquires) {
            for (;;) {
                int available = getState(); // 获取当前可用许可数
                int remaining = available - acquires; // 计算剩余许可数
                // 如果剩余许可数为负或CAS更新成功
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining >= 0; // 返回是否获取成功
            }
        }

        /**
         * 释放许可
         * @param releases 要释放的许可数量
         * @return 总是返回true(共享模式)
         * 
         * 释放过程:
         * 1. 增加许可数量
         * 2. 唤醒等待队列中的线程
         * 3. 返回true表示需要唤醒等待线程
         * 
         * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(高竞争)
         * 线程安全性:完全原子性
         */
        protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState(); // 获取当前许可数
                int next = current + releases; // 计算新的许可数
                // 检查是否溢出
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                // CAS操作更新许可数
                if (compareAndSetState(current, next))
                    return true; // 返回true表示需要唤醒等待线程
            }
        }

        /**
         * 减少许可数量(不阻塞)
         * 这是一个特殊的操作,用于减少许可数量而不获取许可
         * @param reductions 要减少的许可数量
         * 
         * 减少过程:
         * 1. 减少许可数量
         * 2. 使用CAS操作保证原子性
         * 3. 如果减少后许可数为负,抛出异常
         * 
         * 使用场景:
         * - 动态调整信号量的容量
         * - 实现资源的动态缩减
         * - 模拟资源的永久性减少
         */
        final void reducePermits(int reductions) {
            for (;;) {
                int current = getState(); // 获取当前许可数
                int next = current - reductions; // 计算新的许可数
                // 检查参数有效性
                if (next > current) // underflow
                    throw new Error("Permit count underflow");
                // CAS操作更新许可数
                if (compareAndSetState(current, next))
                    return;
            }
        }

        /**
         * 获取并清空所有许可
         * 这是一个特殊的操作,用于获取所有可用许可并将许可数清零
         * @return 获取到的许可数量
         * 
         * 获取过程:
         * 1. 获取当前所有可用许可
         * 2. 将许可数清零
         * 3. 返回获取到的许可数量
         * 
         * 使用场景:
         * - 实现紧急模式
         * - 清空信号量状态
         * - 实现特殊的安全机制
         */
        final int drainPermits() {
            for (;;) {
                int current = getState(); // 获取当前许可数
                // 如果没有许可可用,返回0
                if (current == 0 || compareAndSetState(current, 0))
                    return current; // 返回获取到的许可数量
            }
        }
    }

    /**
     * 非公平同步器实现
     * 允许插队,性能更好但可能导致线程饥饿
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -2694183684443567898L;

        /**
         * 构造方法
         * @param permits 初始许可数量
         */
        NonfairSync(int permits) {
            super(permits);
        }

        /**
         * 尝试获取共享锁(非公平)
         * @param acquires 要获取的许可数量
         * @return 如果获取成功返回正数,否则返回负数
         * 
         * 获取过程:
         * 1. 调用非公平获取方法
         * 2. 返回获取结果
         */
        protected int tryAcquireShared(int acquires) {
            return nonfairTryAcquireShared(acquires);
        }
    }

    /**
     * 公平同步器实现
     * 按照等待顺序获取许可,避免线程饥饿
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = 2014338818796000944L;

        /**
         * 构造方法
         * @param permits 初始许可数量
         */
        FairSync(int permits) {
            super(permits);
        }

        /**
         * 尝试获取共享锁(公平)
         * @param acquires 要获取的许可数量
         * @return 如果获取成功返回正数,否则返回负数
         * 
         * 公平获取过程:
         * 1. 检查是否有前驱节点(确保公平性)
         * 2. 如果没有前驱节点,调用非公平获取方法
         * 3. 返回获取结果
         */
        protected int tryAcquireShared(int acquires) {
            for (;;) {
                // hasQueuedPredecessors()检查是否有前驱节点
                if (hasQueuedPredecessors())
                    return -1; // 有前驱节点,获取失败
                // 调用非公平获取方法
                if (nonfairTryAcquireShared(acquires))
                    return 1; // 获取成功
                return -1; // 获取失败
            }
        }
    }

2. 构造方法(详细注释)

    /**
     * 默认构造方法(非公平)
     * 创建一个指定许可数量的Semaphore
     * @param permits 初始许可数量
     * 
     * 初始化过程:
     * 1. 验证permit参数的有效性
     * 2. 创建NonfairSync实例
     * 3. 初始化许可数量
     * 
     * 参数说明:
     * - permits必须为非负数
     * - permits=0表示初始时没有可用许可
     * - permits>0表示初始时有指定数量的可用许可
     * 
     * @throws IllegalArgumentException 如果permits为负数
     */
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

    /**
     * 指定公平策略的构造方法
     * @param permits 初始许可数量
     * @param fair 是否使用公平策略
     * 
     * 公平性说明:
     * - fair=true:使用公平锁,按照请求顺序获取许可
     * - fair=false:使用非公平锁,允许插队,性能更好
     * 
     * 选择建议:
     * - 高并发场景:使用非公平锁(默认)
     * - 需要避免饥饿:使用公平锁
     * - 对性能要求极高:使用非公平锁
     * 
     * @throws IllegalArgumentException 如果permits为负数
     */
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

3. 核心获取方法(详细注释)

    /**
     * 获取一个许可
     * 如果没有可用许可,当前线程会阻塞直到获取许可
     * 
     * 获取过程:
     * 1. 调用AQS的acquireSharedInterruptibly方法
     * 2. 如果有可用许可,立即获取
     * 3. 如果没有可用许可,加入等待队列并阻塞
     * 4. 被唤醒后重新尝试获取许可
     * 5. 重复步骤2-4直到获取许可
     * 
     * 中断处理:
     * - 如果线程在等待过程中被中断,会抛出InterruptedException
     * - 线程可以被优雅地中止
     * 
     * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(等待时间)
     * 线程安全性:完全线程安全
     * 
     * @throws InterruptedException 如果线程被中断
     */
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1); // 调用AQS的可中断共享获取方法
    }

    /**
     * 获取指定数量的许可
     * 如果没有足够的可用许可,当前线程会阻塞直到获取足够的许可
     * 
     * 获取过程:
     * 1. 调用AQS的acquireSharedInterruptibly方法
     * 2. 如果有足够的可用许可,立即获取
     * 3. 如果没有足够的可用许可,加入等待队列并阻塞
     * 4. 被唤醒后重新尝试获取许可
     * 5. 重复步骤2-4直到获取足够的许可
     * 
     * 参数说明:
     * - permits要获取的许可数量
     * - permits必须为正数
     * 
     * 中断处理:
     * - 如果线程在等待过程中被中断,会抛出InterruptedException
     * - 线程可以被优雅地中止
     * 
     * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(等待时间)
     * 线程安全性:完全线程安全
     * 
     * @param permits 要获取的许可数量
     * @throws InterruptedException 如果线程被中断
     * @throws IllegalArgumentException 如果permits为负数
     */
    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits); // 调用AQS的可中断共享获取方法
    }

    /**
     * 获取一个许可(不可中断)
     * 如果没有可用许可,当前线程会阻塞直到获取许可
     * 
     * 与acquire()的区别:
     * - acquire()可被中断
     * - acquireUninterruptibly()不可被中断
     * 
     * 获取过程:
     * 1. 调用AQS的acquireShared方法
     * 2. 如果有可用许可,立即获取
     * 3. 如果没有可用许可,加入等待队列并阻塞
     * 4. 被唤醒后重新尝试获取许可
     * 5. 重复步骤2-4直到获取许可
     * 
     * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(等待时间)
     * 线程安全性:完全线程安全
     */
    public void acquireUninterruptibly() {
        sync.acquireShared(1); // 调用AQS的共享获取方法
    }

    /**
     * 获取指定数量的许可(不可中断)
     * 如果没有足够的可用许可,当前线程会阻塞直到获取足够的许可
     * 
     * 与acquire(int permits)的区别:
     * - acquire(int permits)可被中断
     * - acquireUninterruptibly(int permits)不可被中断
     * 
     * 获取过程:
     * 1. 调用AQS的acquireShared方法
     * 2. 如果有足够的可用许可,立即获取
     * 3. 如果没有足够的可用许可,加入等待队列并阻塞
     * 4. 被唤醒后重新尝试获取许可
     * 5. 重复步骤2-4直到获取足够的许可
     * 
     * 参数说明:
     * - permits要获取的许可数量
     * - permits必须为正数
     * 
     * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(等待时间)
     * 线程安全性:完全线程安全
     * 
     * @param permits 要获取的许可数量
     * @throws IllegalArgumentException 如果permits为负数
     */
    public void acquireUninterruptibly(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireShared(permits); // 调用AQS的共享获取方法
    }

    /**
     * 尝试获取一个许可(非阻塞)
     * 立即返回,不会阻塞当前线程
     * 
     * 获取结果:
     * - 如果有可用许可,立即获取并返回true
     * - 如果没有可用许可,立即返回false
     * 
     * 使用场景:
     * - 避免线程阻塞
     * - 实现超时控制
     * - 检查许可状态
     * 
     * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(高竞争)
     * 线程安全性:完全原子性
     * 
     * @return 如果获取成功返回true,否则返回false
     */
    public boolean tryAcquire() {
        return sync.nonfairTryAcquireShared(1) >= 0;
    }

    /**
     * 尝试获取指定数量的许可(非阻塞)
     * 立即返回,不会阻塞当前线程
     * 
     * 获取结果:
     * - 如果有足够的可用许可,立即获取并返回true
     * - 如果没有足够的可用许可,立即返回false
     * 
     * 使用场景:
     * - 避免线程阻塞
     * - 实现超时控制
     * - 检查许可状态
     * 
     * 参数说明:
     * - permits要获取的许可数量
     * - permits必须为正数
     * 
     * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(高竞争)
     * 线程安全性:完全原子性
     * 
     * @param permits 要获取的许可数量
     * @return 如果获取成功返回true,否则返回false
     * @throws IllegalArgumentException 如果permits为负数
     */
    public boolean tryAcquire(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.nonfairTryAcquireShared(permits) >= 0;
    }

    /**
     * 尝试获取一个许可(带超时)
     * 如果没有可用许可,等待指定时间
     * 
     * 超时处理:
     * - 在指定时间内获取许可,返回true
     * - 超时未获取到许可,返回false
     * - 等待过程中可被中断
     * 
     * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(等待时间)
     * 线程安全性:完全原子性
     * 
     * @param timeout 等待时间
     * @param unit 时间单位
     * @return 如果获取成功返回true,否则返回false
     * @throws InterruptedException 如果线程被中断
     */
    public boolean tryAcquire(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

    /**
     * 尝试获取指定数量的许可(带超时)
     * 如果没有足够的可用许可,等待指定时间
     * 
     * 超时处理:
     * - 在指定时间内获取足够的许可,返回true
     * - 超时未获取到足够的许可,返回false
     * - 等待过程中可被中断
     * 
     * 参数说明:
     * - permits要获取的许可数量
     * - permits必须为正数
     * - timeout等待时间
     * - unit时间单位
     * 
     * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(等待时间)
     * 线程安全性:完全原子性
     * 
     * @param permits 要获取的许可数量
     * @param timeout 等待时间
     * @param unit 时间单位
     * @return 如果获取成功返回true,否则返回false
     * @throws InterruptedException 如果线程被中断
     * @throws IllegalArgumentException 如果permits为负数
     */
    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
    }

4. 核心释放方法(详细注释)

    /**
     * 释放一个许可
     * 将一个许可返回给信号量,增加可用许可数量
     * 
     * 释放过程:
     * 1. 调用AQS的releaseShared方法
     * 2. 增加许可数量
     * 3. 唤醒等待队列中的线程
     * 4. 允许等待线程获取许可
     * 
     * 注意事项:
     * - 可以释放比初始许可数更多的许可
     * - 释放的许可可以被其他线程获取
     * - 没有限制哪个线程可以释放许可
     * 
     * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(高竞争)
     * 线程安全性:完全原子性
     */
    public void release() {
        sync.releaseShared(1); // 调用AQS的共享释放方法
    }

    /**
     * 释放指定数量的许可
     * 将指定数量的许可返回给信号量,增加可用许可数量
     * 
     * 释放过程:
     * 1. 调用AQS的releaseShared方法
     * 2. 增加指定数量的许可
     * 3. 唤醒等待队列中的线程
     * 4. 允许等待线程获取许可
     * 
     * 参数说明:
     * - permits要释放的许可数量
     * - permits必须为正数
     * 
     * 注意事项:
     * - 可以释放比初始许可数更多的许可
     * - 释放的许可可以被其他线程获取
     * - 没有限制哪个线程可以释放许可
     * 
     * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(高竞争)
     * 线程安全性:完全原子性
     * 
     * @param permits 要释放的许可数量
     * @throws IllegalArgumentException 如果permits为负数
     */
    public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.releaseShared(permits); // 调用AQS的共享释放方法
    }

5. 查询和控制方法(详细注释)

    /**
     * 获取当前可用的许可数量
     * 返回当前信号量中可用的许可数量
     * 
     * 查询过程:
     * 1. 调用sync的getPermits方法
     * 2. 获取AQS的state字段值
     * 3. 返回当前可用许可数
     * 
     * 注意事项:
     * - 这是一个瞬时值,可能很快过时
     * - 在高并发环境下可能不是准确值
     * - 主要用于调试和监控
     * 
     * 时间复杂度:O(1)
     * 线程安全性:完全线程安全
     * 
     * @return 当前可用的许可数量
     */
    public int availablePermits() {
        return sync.getPermits();
    }

    /**
     * 获取并清空所有许可
     * 获取当前所有可用的许可并将许可数清零
     * 
     * 获取过程:
     * 1. 调用sync的drainPermits方法
     * 2. 获取当前所有可用许可
     * 3. 将许可数清零
     * 4. 返回获取到的许可数量
     * 
     * 使用场景:
     * - 实现紧急模式
     * - 清空信号量状态
     * - 实现特殊的安全机制
     * 
     * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(高竞争)
     * 线程安全性:完全原子性
     * 
     * @return 获取到的许可数量
     */
    public int drainPermits() {
        return sync.drainPermits();
    }

    /**
     * 减少许可数量
     * 减少指定数量的许可,不获取许可
     * 
     * 减少过程:
     * 1. 调用sync的reducePermits方法
     * 2. 减少指定数量的许可
     * 3. 使用CAS操作保证原子性
     * 4. 如果减少后许可数为负,抛出异常
     * 
     * 使用场景:
     * - 动态调整信号量的容量
     * - 实现资源的动态缩减
     * - 模拟资源的永久性减少
     * 
     * 参数说明:
     * - reduction要减少的许可数量
     * - reduction必须为非负数
     * 
     * 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(高竞争)
     * 线程安全性:完全原子性
     * 
     * @param reduction 要减少的许可数量
     * @throws IllegalArgumentException 如果reduction为负数
     */
    protected void reducePermits(int reduction) {
        if (reduction < 0) throw new IllegalArgumentException();
        sync.reducePermits(reduction);
    }

    /**
     * 判断是否有线程正在等待获取许可
     * 检查AQS的等待队列中是否有线程
     * 
     * 查询结果:
     * - 如果有等待线程返回true
     * - 如果没有等待线程返回false
     * 
     * 使用场景:
     * - 监控信号量的使用情况
     * - 实现负载监控
     * - 性能调优
     * 
     * 时间复杂度:O(1)
     * 线程安全性:完全线程安全
     * 
     * @return 如果有等待线程返回true,否则返回false
     */
    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    /**
     * 获取等待获取许可的线程数量
     * 返回AQS等待队列中的线程数量
     * 
     * 查询结果:
     * - 返回等待队列中的线程数量
     * - 这是一个估算值,因为线程状态可能随时变化
     * 
     * 使用场景:
     * - 监控信号量的竞争程度
     * - 实现负载监控
     * - 性能调优
     * 
     * 时间复杂度:O(1)
     * 线程安全性:完全线程安全
     * 
     * @return 等待线程数量
     */
    public final int getQueueLength() {
        return sync.getQueueLength();
    }

    /**
     * 获取等待获取许可的线程集合
     * 返回AQS等待队列中线程的集合
     * 
     * 查询结果:
     * - 返回等待队列中线程的集合
     * - 集合是线程安全的快照
     * 
     * 使用场景:
     * - 调试和诊断
     * - 实现管理工具
     * - 分析系统状态
     * 
     * 时间复杂度:O(n) n为等待线程数
     * 线程安全性:完全线程安全
     * 
     * @return 等待线程集合
     */
    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }

6. ReentrantReadWriteLock 的特点分析

核心设计理念:

/**
 * ReentrantReadWriteLock的核心设计思想:
 * 
 * 1. 读写分离:
 *    - 读锁:共享锁,多个读线程可以同时持有
 *    - 写锁:独占锁,写线程独占访问
 *    - 读读不互斥,读写互斥,写写互斥
 * 
 * 2. 可重入性:
 *    - 支持读锁和写锁的可重入
 *    - 每个线程维护自己的持有计数
 *    - 完全释放时才允许其他线程获取
 * 
 * 3. 锁降级:
 *    - 支持写锁降级为读锁
 *    - 先获取写锁,再获取读锁,最后释放写锁
 *    - 保证数据的一致性
 * 
 * 4. 公平性选择:
 *    - 提供公平和非公平两种模式
 *    - 公平锁避免线程饥饿
 *    - 非公平锁提高性能
 * 
 * 5. 线程本地存储:
 *    - 使用ThreadLocal跟踪每个线程的读锁持有情况
 *    - 避免竞争和同步开销
 *    - 优化单个读线程的场景
 * 
 * 6. AQS集成:
 *    - 继承AbstractQueuedSynchronizer
 *    - 复用成熟的队列管理机制
 *    - 提供完整的同步框架
 * 
 * 适用场景:
 * - 读操作远多于写操作的场景
 * - 需要高并发读取的场景
 * - 需要比ReentrantLock更细粒度控制的场景
 * - 需要Condition支持的写锁场景
 */

性能特征分析:

/**
 * ReentrantReadWriteLock的性能特征:
 * 
 * 获取锁时间复杂度:
 * - 无竞争读锁:O(1) - 直接CAS操作
 * - 无竞争写锁:O(1) - 直接CAS操作
 * - 有竞争:O(1) 平均,O(n) 最坏(等待队列长度)
 * 
 * 释放锁时间复杂度:
 * - 读锁释放:O(1) - 更新状态并可能唤醒写锁
 * - 写锁释放:O(1) - 更新状态并唤醒等待线程
 * 
 * 内存复杂度:
 * - O(1) 基本开销
 * - O(n) 等待队列开销(n为等待线程数)
 * - O(t) ThreadLocal开销(t为持有读锁的线程数)
 * 
 * 并发特性:
 * - 完全线程安全
 * - 支持高并发读取
 * - 读写互斥保证数据一致性
 * - 无锁设计(通过CAS和AQS)
 * 
 * 读写性能对比:
 * - 读锁:多个线程可以并发获取
 * - 写锁:独占访问,性能相对较低
 * - 读多写少:性能优势明显
 * - 写多读少:可能不如ReentrantLock
 * 
 * 公平性对比:
 * - 非公平锁:吞吐量更高,可能有线程饥饿
 * - 公平锁:避免饥饿,吞吐量略低
 * 
 * 与ReentrantLock对比:
 * - 读写分离:更细粒度的控制
 * - 读并发:支持多个读线程同时访问
 * - 复杂度:实现更复杂,开销略大
 * - 适用场景:读多写少的场景
 */

7. 使用示例和最佳实践

/**
 * 使用示例:
 * 
 * // 基本使用
 * ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
 * Lock readLock = rwLock.readLock();
 * Lock writeLock = rwLock.writeLock();
 * 
 * // 读操作
 * readLock.lock();
 * try {
 *     // 读取共享数据
 *     // 多个读线程可以同时执行
 * } finally {
 *     readLock.unlock();
 * }
 * 
 * // 写操作
 * writeLock.lock();
 * try {
 *     // 修改共享数据
 *     // 独占访问,其他读写操作都会阻塞
 * } finally {
 *     writeLock.unlock();
 * }
 * 
 * // 可中断的锁获取
 * try {
 *     readLock.lockInterruptibly();
 *     try {
 *         // 读操作
 *     } finally {
 *         readLock.unlock();
 *     }
 * } catch (InterruptedException e) {
 *     Thread.currentThread().interrupt();
 * }
 * 
 * // 带超时的锁获取
 * try {
 *     if (writeLock.tryLock(5, TimeUnit.SECONDS)) {
 *         try {
 *             // 写操作
 *         } finally {
 *             writeLock.unlock();
 *         }
 *     } else {
 *         // 获取锁超时
 *         System.out.println("Failed to acquire write lock within timeout");
 *     }
 * } catch (InterruptedException e) {
 *     Thread.currentThread().interrupt();
 * }
 * 
 * // 公平锁
 * ReentrantReadWriteLock fairRwLock = new ReentrantReadWriteLock(true);
 * 
 * // 使用Condition(仅写锁支持)
 * Condition condition = writeLock.newCondition();
 * 
 * // 等待条件
 * writeLock.lock();
 * try {
 *     while (!conditionMet()) {
 *         condition.await();
 *     }
 *     // 条件满足后的处理
 * } finally {
 *     writeLock.unlock();
 * }
 * 
 * // 通知等待的线程
 * writeLock.lock();
 * try {
 *     // 改变条件
 *     setConditionMet(true);
 *     condition.signal(); // 或者 condition.signalAll();
 * } finally {
 *     writeLock.unlock();
 * }
 * 
 * 最佳实践:
 * 
 * 1. 正确的锁获取和释放:
 *    ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
 *    Lock readLock = rwLock.readLock();
 *    Lock writeLock = rwLock.writeLock();
 *    
 *    // 读操作
 *    readLock.lock();
 *    try {
 *        // 读取操作
 *    } finally {
 *        readLock.unlock(); // 必须在finally块中释放
 *    }
 *    
 *    // 写操作
 *    writeLock.lock();
 *    try {
 *        // 写入操作
 *    } finally {
 *        writeLock.unlock(); // 必须在finally块中释放
 *    }
 * 
 * 2. 避免读写锁嵌套:
 *    // 错误的做法:可能导致死锁
 *    readLock.lock();
 *    try {
 *        // 一些操作
 *        if (needToUpdate()) {
 *            writeLock.lock(); // 危险!可能导致死锁
 *            try {
 *                // 更新操作
 *            } finally {
 *                writeLock.unlock();
 *            }
 *        }
 *    } finally {
 *        readLock.unlock();
 *    }
 *    
 *    // 正确的做法:统一使用写锁
 *    writeLock.lock();
 *    try {
 *        // 读取操作
 *        // 更新操作
 *    } finally {
 *        writeLock.unlock();
 *    }
 * 
 * 3. 合理使用可重入性:
 *    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
 *    private final Lock readLock = rwLock.readLock();
 *    private final Lock writeLock = rwLock.writeLock();
 *    
 *    public void outerReadMethod() {
 *        readLock.lock();
 *        try {
 *            innerReadMethod(); // 同一线程可以再次获取读锁
 *        } finally {
 *            readLock.unlock(); // 只需要一次unlock
 *        }
 *    }
 *    
 *    public void innerReadMethod() {
 *        readLock.lock();
 *        try {
 *            // 读取操作
 *            System.out.println("Read hold count: " + rwLock.getReadHoldCount());
 *        } finally {
 *            readLock.unlock();
 *        }
 *    }
 * 
 * 4. 选择合适的公平性:
 *    // 读多写少且对公平性要求不高:非公平锁(默认)
 *    ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
 *    
 *    // 需要避免饥饿:公平锁
 *    ReentrantReadWriteLock fairRwLock = new ReentrantReadWriteLock(true);
 * 
 * 5. 设置合理的超时时间:
 *    try {
 *        if (readLock.tryLock(10, TimeUnit.SECONDS)) {
 *            try {
 *                // 读操作
 *            } finally {
 *                readLock.unlock();
 *            }
 *        } else {
 *            // 超时处理
 *            System.out.println("Read operation timed out");
 *        }
 *    } catch (InterruptedException e) {
 *        Thread.currentThread().interrupt();
 *    }
 * 
 * 6. 监控锁的使用情况:
 *    ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
 *    
 *    // 检查锁的状态
 *    if (rwLock.isWriteLocked()) {
 *        System.out.println("Write lock is currently held");
 *    }
 *    
 *    if (rwLock.isWriteLockedByCurrentThread()) {
 *        System.out.println("Current thread holds the write lock");
 *        System.out.println("Write hold count: " + rwLock.getWriteHoldCount());
 *    }
 *    
 *    System.out.println("Read lock count: " + rwLock.getReadLockCount());
 *    System.out.println("Current thread read hold count: " + rwLock.getReadHoldCount());
 *    
 *    // 检查等待队列
 *    if (rwLock.hasQueuedThreads()) {
 *        System.out.println("Threads waiting for lock: " + rwLock.getQueueLength());
 *    }
 * 
 * 7. 使用Condition(仅写锁支持):
 *    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
 *    private final Lock writeLock = rwLock.writeLock();
 *    private final Condition notFull = writeLock.newCondition();
 *    private final Condition notEmpty = writeLock.newCondition();
 *    
 *    // 生产者
 *    public void put(Object item) throws InterruptedException {
 *        writeLock.lock();
 *        try {
 *            while (isFull()) {
 *                notFull.await(); // 等待空间
 *            }
 *            // 添加元素
 *            notEmpty.signal(); // 通知消费者
 *        } finally {
 *            writeLock.unlock();
 *        }
 *    }
 *    
 *    // 消费者
 *    public Object take() throws InterruptedException {
 *        writeLock.lock();
 *        try {
 *            while (isEmpty()) {
 *                notEmpty.await(); // 等待元素
 *            }
 *            Object item = remove(); // 移除元素
 *            notFull.signal(); // 通知生产者
 *            return item;
 *        } finally {
 *            writeLock.unlock();
 *        }
 *    }
 * 
 * 8. 避免长时间持有锁:
 *    // 错误的做法:长时间持有锁
 *    writeLock.lock();
 *    try {
 *        // 大量计算或I/O操作
 *        expensiveOperation(); // 不应该在锁内执行
 *        // 更新共享数据
 *    } finally {
 *        writeLock.unlock();
 *    }
 *    
 *    // 正确的做法:减少锁持有时间
 *    Object result = expensiveOperation(); // 在锁外执行
 *    writeLock.lock();
 *    try {
 *        // 只在必要时持有锁
 *        updateSharedData(result);
 *    } finally {
 *        writeLock.unlock();
 *    }
 * 
 * 9. 处理异常:
 *    ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
 *    Lock readLock = rwLock.readLock();
 *    
 *    readLock.lock();
 *    try {
 *        // 可能抛出异常的代码
 *        riskyReadOperation();
 *    } catch (Exception e) {
 *        // 处理异常
 *        System.err.println("Read operation failed: " + e.getMessage());
 *        throw e; // 重新抛出或处理
 *    } finally {
 *        readLock.unlock(); // 确保锁被释放
 *    }
 * 
 * 10. 性能调优:
 *    // 在高并发读场景下监控性能
 *    ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
 *    
 *    // 定期检查锁的使用情况
 *    if (rwLock.getReadLockCount() > 1000) {
 *        System.out.println("High read contention detected");
 *        // 可能需要优化数据结构或访问模式
 *    }
 *    
 *    if (rwLock.getQueueLength() > 100) {
 *        System.out.println("High lock contention detected");
 *        // 可能需要减少锁的粒度
 *    }
 */

8. 与其他同步机制的比较

/**
 * ReentrantReadWriteLock vs ReentrantLock vs synchronized vs StampedLock:
 * 
 * ReentrantReadWriteLock:
 * - 读写分离,读读不互斥
 * - 支持多个读线程并发访问
 * - 写锁独占访问
 * - 支持公平性和非公平性
 * - 读锁不支持Condition
 * - 写锁支持Condition
 * 
 * ReentrantLock:
 * - 独占锁,读写都互斥
 * - 不区分读写操作
 * - 支持公平性和非公平性
 * - 支持Condition
 * - 实现相对简单
 * 
 * synchronized:
 * - JVM内置锁
 * - 自动释放锁
 * - JVM优化(偏向锁、轻量级锁等)
 * - 不支持读写分离
 * - 不支持公平性选择
 * - 不支持Condition(Object的wait/notify)
 * 
 * StampedLock:
 * - JDK 8新增
 * - 更高性能的读写锁
 * - 支持乐观读
 * - 不支持重入
 * - 不支持Condition
 * - 更复杂的使用方式
 * 
 * 选择建议:
 * - 读多写少:ReentrantReadWriteLock
 * - 简单同步需求:synchronized
 * - 需要Condition:ReentrantLock
 * - 高性能读操作:StampedLock
 * - 复杂同步逻辑:ReentrantLock
 * 
 * 性能对比:
 * - 无竞争:synchronized ≈ ReentrantLock ≈ ReentrantReadWriteLock
 * - 有竞争:ReentrantLock ≥ synchronized(JDK 1.6后)
 * - 读多写少:ReentrantReadWriteLock > ReentrantLock > synchronized
 * - 高并发读:StampedLock > ReentrantReadWriteLock
 * - 写多读少:ReentrantLock ≥ ReentrantReadWriteLock
 */

9. 总结

ReentrantReadWriteLock 的核心特性:

  1. 读写分离

    • 读锁:共享锁,多个读线程可以同时持有
    • 写锁:独占锁,写线程独占访问
    • 读读不互斥,读写互斥,写写互斥
  2. 可重入性

    • 支持读锁和写锁的可重入
    • 每个线程维护自己的持有计数
    • 完全释放时才允许其他线程获取
  3. 锁降级

    • 支持写锁降级为读锁
    • 先获取写锁,再获取读锁,最后释放写锁
    • 保证数据的一致性
  4. 公平性选择

    • 提供公平和非公平两种模式
    • 公平锁避免线程饥饿
    • 非公平锁提高性能
  5. 线程本地存储

    • 使用ThreadLocal跟踪每个线程的读锁持有情况
    • 避免竞争和同步开销
    • 优化单个读线程的场景
  6. AQS集成

    • 继承AbstractQueuedSynchronizer
    • 复用成熟的队列管理机制
    • 提供完整的同步框架
  7. Condition支持

    • 写锁支持Condition
    • 提供灵活的线程等待/通知机制
    • 不支持读锁的Condition
  8. 丰富的查询API

    • 提供详细的锁状态查询
    • 支持监控和诊断
    • 便于调试和性能调优

适用场景:

  • 读操作远多于写操作的场景
  • 需要高并发读取的场景
  • 需要比ReentrantLock更细粒度控制的场景
  • 需要Condition支持的写锁场景
  • 缓存系统、数据库访问等读多写少的应用

注意事项:

  • 必须在finally块中释放锁
  • 避免读写锁嵌套导致死锁
  • 合理选择公平性策略
  • 正确处理中断异常
  • 监控锁的使用情况
  • 避免长时间持有锁
  • 注意读写锁的语义区别

性能优化建议:

  1. 根据读写比例选择合适的锁类型
  2. 合理设置超时时间
  3. 使用公平锁避免线程饥饿
  4. 监控锁的竞争情况
  5. 优化临界区代码减少持有时间
  6. 考虑使用更细粒度的锁
  7. 定期分析和调优锁的使用
  8. 在读多写少的场景下充分发挥读并发优势
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值