Java并发编程之Lock锁机制深度解析:从使用到源码实现

1. 锁的基本概念:从现实世界到代码世界

1.1 锁的演进:synchronized → Lock

想象一下健身房储物柜的使用场景:

  • synchronized:像固定密码锁 - 简单易用但功能有限
  • Lock接口:像智能电子锁 - 功能丰富且灵活可控
// synchronized - 固定密码锁
public synchronized void oldMethod() {
    // 自动上锁和解锁
    // 但无法中断、无法超时、无法尝试获取
}

// Lock - 智能电子锁  
public void newMethod() {
    Lock lock = new ReentrantLock();
    lock.lock();  // 手动开锁
    try {
        // 临界区代码
    } finally {
        lock.unlock();  // 手动关锁
    }
}

1.2 Lock接口的核心优势

特性 synchronized Lock
中断响应
超时控制
尝试获取
公平性
条件队列 单个 多个

2. AQS:并发世界的交通指挥中心

2.1 AQS的核心设计思想

AQS(AbstractQueuedSynchronizer)就像高速公路收费站系统

  • state状态:当前可通行的车道数量
  • 同步队列:等待通行的车辆排队
  • CAS操作:智能的车辆调度系统
/**
 * AQS同步状态管理示例
 */
public class AQSCoreConcept {
    // state字段的三种典型用法:
    
    // 1. 互斥锁:state = 0(未锁定) 或 1(已锁定)
    // 2. 重入锁:state = 重入次数  
    // 3. 读写锁:高16位 = 读锁计数,低16位 = 写锁计数
    private volatile int state;
    
    // 三个核心的state操作方法:
    protected final int getState() { return state; }
    protected final void setState(int newState) { state = newState; }
    protected final boolean compareAndSetState(int expect, int update) {
        // CAS原子操作,保证线程安全
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }
}

2.2 同步队列:线程的"等候区"

/**
 * AQS同步队列结构演示
 */
public class SyncQueueDemo {
    /**
     * 同步队列节点结构(双向链表):
     * 
     * head (虚拟节点) ↔ [prev|thread|next|waitStatus] ↔ [prev|thread|next|waitStatus] ↔ tail
     * 
     * waitStatus状态说明:
     * - CANCELLED(1):线程已取消
     * - SIGNAL(-1):后继线程需要被唤醒  
     * - CONDITION(-2):线程在Condition队列中
     * - PROPAGATE(-3):共享模式下传播唤醒
     */
    
    // 独占模式获取锁的典型流程
    public void acquireDemo() {
        Lock lock = new ReentrantLock();
        
        // 底层调用AQS的acquire方法
        lock.lock();  // -> sync.acquire(1);
        
        /**
         * acquire方法执行流程:
         * 1. tryAcquire()尝试直接获取锁
         * 2. 失败 → addWaiter()加入同步队列队尾
         * 3. acquireQueued()在队列中自旋等待
         * 4. 被前驱节点唤醒后重新尝试获取锁
         */
    }
}

2.3 自定义锁实战:基于AQS实现TwinsLock

/**
 * TwinsLock - 同一时刻最多允许两个线程访问的共享锁
 * 设计思路:将AQS的state作为许可证计数器
 */
public class TwinsLock implements Lock {
    private final Sync sync = new Sync(2);
    
    private static final class Sync extends AbstractQueuedSynchronizer {
        Sync(int count) {
            if (count <= 0) throw new IllegalArgumentException("计数必须大于0");
            setState(count);  // 初始化许可证数量
        }
        
        /**
         * 共享模式获取锁
         * @return 负数:获取失败;0:获取成功但无剩余;正数:获取成功且有剩余
         */
        @Override
        public int tryAcquireShared(int reduceCount) {
            for (;;) {  // 自旋避免CAS失败
                int current = getState();
                int newCount = current - reduceCount;
                
                // 如果新计数<0(无许可证)或CAS设置成功,返回结果
                if (newCount < 0 || compareAndSetState(current, newCount)) {
                    return newCount;
                }
            }
        }
        
        /**
         * 共享模式释放锁
         */
        @Override
        public boolean tryReleaseShared(int returnCount) {
            for (;;) {
                int current = getState();
                int newCount = current + returnCount;
                if (compareAndSetState(current, newCount)) {
                    return true;
                }
            }
        }
    }
    
    @Override
    public void lock() {
        sync.acquireShared(1);  // 获取1个许可证
    }
    
    @Override
    public void unlock() {
        sync.releaseShared(1);  // 释放1个许可证
    }
    
    // 其他Lock方法实现...
}

/**
 * 测试TwinsLock
 */
public class TwinsLockTest {
    @Test
    public void testTwinsLock() {
        final Lock lock = new TwinsLock();
        
        // 启动10个线程,但同一时刻只有2个能获取锁
        for (int i = 0; i < 10; i++) {
            Thread worker = new Thread(() -> {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " 获取锁");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    lock.unlock();
                }
            });
            worker.start();
        }
    }
}

3. 重入锁ReentrantLock:可重复使用的智能锁

3.1 重入性:一把钥匙开多把锁

现实比喻:你进了自家大门,还可以用同一把钥匙打开卧室门、书房门。

/**
 * 重入锁的重入特性演示
 */
public class ReentrantDemo {
    private final ReentrantLock lock = new ReentrantLock();
    
    public void outer() {
        lock.lock();
        try {
            System.out.println("外层方法获取锁,重入计数: " + getHoldCount());
            inner();  // 重入:同一个线程再次获取同一把锁
        } finally {
            lock.unlock();
        }
    }
    
    public void inner() {
        lock.lock();  // 这里不会阻塞,因为已经是锁的持有者
        try {
            System.out.println("内层方法获取锁,重入计数: " + getHoldCount());
        } finally {
            lock.unlock();
        }
    }
    
    private int getHoldCount() {
        // 返回当前线程持有该锁的次数
        return lock.getHoldCount();
    }
}

3.2 公平锁 vs 非公平锁

公平锁:像银行取号排队 - 先来先服务
非公平锁:像公交车抢座位 - 谁能抢到谁坐

/**
 * 公平性对比测试
 */
public class FairVsUnfairTest {
    private static Lock fairLock = new ReentrantLock(true);      // 公平锁
    private static Lock unfairLock = new ReentrantLock(false);   // 非公平锁
    
    @Test
    public void comparePerformance() {
        // 测试结果通常显示:
        // - 公平锁:保证顺序,但性能较低
        // - 非公平锁:可能饥饿,但吞吐量高
        
        testLock("公平锁", fairLock);
        testLock("非公平锁", unfairLock);
    }
    
    private void testLock(String type, Lock lock) {
        long start = System.currentTimeMillis();
        
        // 多个线程竞争锁...
        
        long duration = System.currentTimeMillis() - start;
        System.out.println(type + " 耗时: " + duration + "ms");
    }
}

3.3 重入锁实现原理

/**
 * 重入锁核心实现解析
 */
public class ReentrantLockCore {
    /**
     * 非公平锁获取逻辑
     */
    final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        
        if (c == 0) {  // 锁空闲
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        } else if (current == getExclusiveOwnerThread()) {  // 重入
            int nextc = c + acquires;
            if (nextc < 0) throw new Error("超过最大锁计数");
            setState(nextc);  // 增加重入计数
            return true;
        }
        return false;
    }
    
    /**
     * 释放锁逻辑
     */
    protected final boolean tryRelease(int releases) {
        int c = getState() - releases;
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
            
        boolean free = false;
        if (c == 0) {  // 完全释放
            free = true;
            setExclusiveOwnerThread(null);
        }
        setState(c);
        return free;
    }
}

4. 读写锁ReentrantReadWriteLock:读写分离的高并发锁

4.1 读写锁的应用场景

现实比喻:图书馆管理规则

  • 读操作:多人可同时阅读同一本书
  • 写操作:修改书籍时需独占访问
/**
 * 基于读写锁的缓存实现
 */
public class ReadWriteCache<K, V> {
    private final Map<K, V> cache = new HashMap<>();
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();
    
    /**
     * 读操作:共享锁,允许多个线程同时读
     */
    public V get(K key) {
        readLock.lock();
        try {
            String value = cache.get(key);
            // 模拟配置读取的耗时操作
            simulateProcess(1);
            return value;
        } finally {
            readLock.unlock();
        }
    }
    
    /**
     * 批量获取配置 - 读锁支持并发
     */
    public Map<String, String> getConfigs(Set<String> keys) {
        readLock.lock();
        try {
            Map<String, String> result = new HashMap<>();
            for (String key : keys) {
                result.put(key, cache.get(key));
            }
            simulateProcess(keys.size());
            return result;
        } finally {
            readLock.unlock();
        }
    }
    
    /**
     * 更新配置 - 低频操作,使用写锁
     */
    public void updateConfig(String key, String value) {
        writeLock.lock();
        try {
            // 模拟配置更新的耗时操作
            simulateProcess(10);
            cache.put(key, value);
            System.out.println("配置更新: " + key + " = " + value);
        } finally {
            writeLock.unlock();
        }
    }
    
    private void simulateProcess(int milliseconds) {
        try {
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

4.2 读写锁的状态设计

/**
 * 读写锁状态设计的精妙之处
 */
public class ReadWriteStateDesign {
    /**
     * 32位state字段的划分:
     * 
     * ┌─────────────────┬─────────────────┐
     * │     高16位      │     低16位      │
     * │     读状态      │     写状态      │
     * │   (读锁计数)    │  (写锁重入数)   │
     * └─────────────────┴─────────────────┘
     */
    
    // 获取写状态(低16位)
    static int exclusiveCount(int c) { 
        return c & 0x0000FFFF; 
    }
    
    // 获取读状态(高16位)
    static int sharedCount(int c) { 
        return c >>> 16; 
    }
    
    // 读锁计数+1
    int newReadState = currentState + (1 << 16);  // 即 + 0x00010000
    
    // 写锁计数+1  
    int newWriteState = currentState + 1;
}

4.3 锁降级:保证数据可见性的重要技术

/**
 * 锁降级示例:写锁 → 读锁
 * 目的:保证数据的可见性
 */
public class LockDemotionExample {
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();
    private volatile boolean update = false;
    private Object data;
    
    public void processData() {
        readLock.lock();
        if (!update) {
            // 数据需要更新,必须先释放读锁
            readLock.unlock();
            
            // 获取写锁
            writeLock.lock();
            try {
                // 双重检查
                if (!update) {
                    // 准备数据...
                    data = fetchData();
                    update = true;
                }
                // 关键步骤:在释放写锁前获取读锁
                readLock.lock();  // 锁降级开始
            } finally {
                writeLock.unlock();  // 锁降级完成,现在持有读锁
            }
        }
        
        try {
            // 使用数据(仍在读锁保护下)
            useData(data);
        } finally {
            readLock.unlock();
        }
    }
    
    // 不支持锁升级!可能产生死锁
    public void invalidLockUpgrade() {
        readLock.lock();
        try {
            // 危险操作:尝试在持有读锁时获取写锁
            // 如果其他线程也持有读锁,会产生死锁
            writeLock.lock();  // 可能永远阻塞!
            try {
                // 修改数据...
            } finally {
                writeLock.unlock();
            }
        } finally {
            readLock.unlock();
        }
    }
    
    private Object fetchData() { return null; }
    private void useData(Object data) {}
}

5. LockSupport:线程的精准遥控器

5.1 LockSupport的核心能力

LockSupport提供线程阻塞和唤醒的原子操作,就像线程的远程控制器

/**
 * LockSupport基础使用
 */
public class LockSupportBasic {
    
    public static void main(String[] args) throws InterruptedException {
        Thread worker = new Thread(() -> {
            System.out.println("工作线程开始执行");
            System.out.println("工作线程即将被阻塞");
            
            // 阻塞当前线程(停车)
            LockSupport.park();
            
            System.out.println("工作线程被唤醒,继续执行");
        });
        
        worker.start();
        
        Thread.sleep(2000);  // 主线程等待2秒
        
        System.out.println("主线程准备唤醒工作线程");
        
        // 唤醒指定线程(开车)
        LockSupport.unpark(worker);
        
        System.out.println("主线程已发送唤醒信号");
    }
}

5.2 许可机制:先发后至的灵活性

/**
 * LockSupport的许可机制演示
 * 每个线程有一个许可(最多为1):
 * - unpark:添加一个许可
 * - park:消耗一个许可,没有许可就阻塞
 */
public class PermitMechanism {
    
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("子线程开始");
            
            try {
                Thread.sleep(1000);  // 确保主线程先调用unpark
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            
            System.out.println("子线程调用park");
            
            // 这里不会阻塞,因为主线程已经给了许可
            LockSupport.park();
            System.out.println("子线程第一次park完成");
            
            // 这次会阻塞,因为许可已经被消耗
            LockSupport.park(); 
            System.out.println("子线程第二次park完成");
        });
        
        thread.start();
        
        // 立即给子线程许可(先发)
        System.out.println("主线程调用unpark");
        LockSupport.unpark(thread);
        
        // 等待后再次唤醒
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("主线程再次调用unpark");
        LockSupport.unpark(thread);
    }
}

5.3 Blocker:线程诊断的"身份证"

/**
 * Blocker的作用:在线程dump中标识等待目标
 */
public class BlockerDemo {
    
    public static void main(String[] args) throws InterruptedException {
        Object blocker = new Object();  // 阻塞对象
        
        Thread withBlocker = new Thread(() -> {
            System.out.println("带Blocker的线程开始阻塞");
            // 推荐:使用带blocker的park方法
            LockSupport.park(blocker);  
            System.out.println("带Blocker的线程被唤醒");
        }, "WithBlocker-Thread");
        
        Thread withoutBlocker = new Thread(() -> {
            System.out.println("无Blocker的线程开始阻塞");
            // 不推荐:无blocker的park方法
            LockSupport.park();  
            System.out.println("无Blocker的线程被唤醒");
        }, "WithoutBlocker-Thread");
        
        withBlocker.start();
        withoutBlocker.start();
        
        Thread.sleep(1000);
        
        // 在实际环境中使用jstack查看线程dump,区别明显:
        // 有Blocker: "parking to wait for <0x00000000d5e8a6c0> (a java.lang.Object)"
        // 无Blocker: 只显示在LockSupport.park处等待
        
        LockSupport.unpark(withBlocker);
        LockSupport.unpark(withoutBlocker);
        
        withBlocker.join();
        withoutBlocker.join();
    }
}

6. Condition接口:精准的线程协调器

6.1 Condition vs Object监视器

特性 Object.wait/notify Condition.await/signal
前置条件 必须在synchronized内 必须先获取Lock
等待队列 一个对象一个队列 一个Lock多个Condition
精确通知 只能notifyAll或随机 可以精确通知特定Condition
超时控制 有限支持 丰富的时间控制方法

6.2 Condition实战:有界阻塞队列

/**
 * 有界阻塞队列 - Condition的经典应用
 * 功能:
 * - 队列空时,消费者等待
 * - 队列满时,生产者等待
 */
public class BoundedBlockingQueue<T> {
    private final Object[] items;
    private int addIndex, removeIndex, count;
    
    private final Lock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();  // 非空条件
    private final Condition notFull = lock.newCondition();   // 非满条件
    
    public BoundedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        items = new Object[capacity];
    }
    
    /**
     * 生产方法:队列满时阻塞
     */
    public void put(T item) throws InterruptedException {
        lock.lock();
        try {
            // 使用while防止虚假唤醒
            while (count == items.length) {
                System.out.println("队列已满,生产者等待...");
                notFull.await();  // 在notFull条件上等待
            }
            
            // 生产元素
            items[addIndex] = item;
            if (++addIndex == items.length) addIndex = 0;
            count++;
            
            System.out.println("生产: " + item + ", 当前数量: " + count);
            
            // 通知可能等待的消费者
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 消费方法:队列空时阻塞
     */
    @SuppressWarnings("unchecked")
    public T take() throws InterruptedException {
        lock.lock();
        try {
            // 使用while防止虚假唤醒
            while (count == 0) {
                System.out.println("队列为空,消费者等待...");
                notEmpty.await();  // 在notEmpty条件上等待
            }
            
            // 消费元素
            T item = (T) items[removeIndex];
            if (++removeIndex == items.length) removeIndex = 0;
            count--;
            
            System.out.println("消费: " + item + ", 当前数量: " + count);
            
            // 通知可能等待的生产者
            notFull.signal();
            return item;
        } finally {
            lock.unlock();
        }
    }
}

6.3 Condition内部机制:等待队列与同步队列的协作

/**
 * Condition内部工作机制解析
 */
public class ConditionInternalMechanism {
    /**
     * Condition内部有两个重要队列:
     * 
     * 1. 等待队列(Condition队列):单向链表
     *    firstWaiter → [thread|nextWaiter] → [thread|nextWaiter] → lastWaiter
     *    
     * 2. 同步队列(AQS队列):双向链表  
     *    head ↔ [prev|thread|next] ↔ [prev|thread|next] ↔ tail
     * 
     * await过程:同步队列 → 等待队列
     * signal过程:等待队列 → 同步队列
     */
    
    /**
     * await方法核心流程:
     */
    public final void await() throws InterruptedException {
        // 1. 创建节点加入Condition等待队列
        Node node = addConditionWaiter();
        
        // 2. 完全释放锁(保存重入状态)
        int savedState = fullyRelease(node);
        
        // 3. 阻塞直到被signal或中断
        while (!isOnSyncQueue(node)) {
            LockSupport.park(this);
            if (checkInterruptWhileWaiting(node) != 0) break;
        }
        
        // 4. 被唤醒后重新竞争锁
        if (acquireQueued(node, savedState)) {
            // 处理中断...
        }
    }
    
    /**
     * signal方法核心流程:
     */
    public final void signal() {
        // 1. 必须持有锁才能调用
        if (!isHeldExclusively())
            throw new IllegalMonitorStateException();
            
        // 2. 转移等待队列的第一个节点到同步队列
        Node first = firstWaiter;
        if (first != null)
            doSignal(first);
    }
}

7. AQS同步队列 vs Condition等待队列

7.1 核心区别总结

特性 AQS同步队列 Condition等待队列
设计目的 管理锁竞争的线程 管理条件等待的线程
数据结构 双向链表 单向链表
节点状态 SIGNAL, CANCELLED, 0, PROPAGATE CONDITION(-2)
队列数量 每个AQS实例1个 每个Condition1个
线程行为 竞争锁资源 等待特定条件满足
唤醒方式 前驱节点释放锁时唤醒 其他线程调用signal()唤醒

7.2 队列协作的完整示例

/**
 * 演示两个队列如何协作工作
 */
public class TwoQueuesCollaboration {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    
    public void demonstrate() throws InterruptedException {
        Thread waiter = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Waiter: 获取锁,准备await");
                
                // 此时:
                // - Waiter在同步队列中(持有锁)
                // - 等待队列为空
                
                condition.await();  // 关键操作!
                
                // await内部完成:
                // 1. Waiter节点从同步队列移到等待队列
                // 2. 释放锁
                // 3. 阻塞等待
                
                System.out.println("Waiter: 被唤醒,重新获得锁");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                lock.unlock();
            }
        });
        
        Thread signaler = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Signaler: 获取锁,调用signal");
                
                // 此时:
                // - Signaler在同步队列中(持有锁)  
                // - Waiter在等待队列中
                
                condition.signal();  // 关键操作!
                
                // signal内部完成:
                // 1. Waiter节点从等待队列移到同步队列
                // 2. 唤醒Waiter线程
                
                System.out.println("Signaler: signal完成");
            } finally {
                lock.unlock();  // 释放锁,Waiter有机会竞争锁
            }
        });
        
        waiter.start();
        Thread.sleep(100);  // 确保waiter先执行
        signaler.start();
        
        waiter.join();
        signaler.join();
    }
}

8. 实战指南:如何正确使用Java并发锁

8.1 锁使用的核心原则

原则1:永远在finally块中释放锁

/**
 * 正确的锁释放方式
 */
public class CorrectLockUsage {
    private final Lock lock = new ReentrantLock();
    
    // ✅ 正确做法
    public void correctMethod() {
        lock.lock();
        try {
            // 业务逻辑
            doBusiness();
        } finally {
            lock.unlock();  // 确保锁被释放
        }
    }
    
    // ❌ 错误做法
    public void wrongMethod() {
        lock.lock();
        doBusiness();
        lock.unlock();  // 如果doBusiness抛出异常,锁不会被释放!
    }
    
    private void doBusiness() {
        // 可能抛出异常的业务逻辑
        if (Math.random() > 0.5) {
            throw new RuntimeException("业务异常");
        }
    }
}

原则2:避免锁嵌套,预防死锁

/**
 * 死锁预防示例
 */
public class DeadlockPrevention {
    private final Lock lockA = new ReentrantLock();
    private final Lock lockB = new ReentrantLock();
    
    // ❌ 容易导致死锁的做法
    public void potentialDeadlock() {
        lockA.lock();
        try {
            // 一些操作...
            lockB.lock();  // 如果另一个线程以相反顺序获取锁,可能死锁
            try {
                // 更多操作...
            } finally {
                lockB.unlock();
            }
        } finally {
            lockA.unlock();
        }
    }
    
    // ✅ 使用tryLock避免死锁
    public void safeMethod() {
        while (true) {
            if (lockA.tryLock()) {
                try {
                    if (lockB.tryLock()) {
                        try {
                            // 成功获取两个锁,执行业务
                            doBusiness();
                            return;  // 成功完成,退出循环
                        } finally {
                            lockB.unlock();
                        }
                    }
                } finally {
                    lockA.unlock();
                }
            }
            // 获取锁失败,短暂休息后重试
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
    
    // ✅ 使用固定的锁获取顺序
    public void fixedOrderMethod(Object resource1, Object resource2) {
        // 通过hash值确定固定的获取顺序
        int hash1 = System.identityHashCode(resource1);
        int hash2 = System.identityHashCode(resource2);
        
        if (hash1 < hash2) {
            lockA.lock();
            lockB.lock();
        } else {
            lockB.lock();
            lockA.lock();
        }
        
        try {
            doBusiness();
        } finally {
            lockA.unlock();
            lockB.unlock();
        }
    }
    
    private void doBusiness() {}
}

8.2 各组件最佳实践案例

8.2.1 ReentrantLock最佳实践:连接池管理

/**
 * 基于ReentrantLock的简单数据库连接池
 * 特性:支持超时获取、中断响应、连接验证
 */
public class DatabaseConnectionPool {
    private final LinkedList<Connection> pool = new LinkedList<>();
    private final ReentrantLock lock = new ReentrantLock(true);  // 公平锁
    private final Condition notEmpty = lock.newCondition();
    private final int maxSize;
    private final long maxWaitTime;
    
    public DatabaseConnectionPool(int maxSize, long maxWaitMillis) {
        this.maxSize = maxSize;
        this.maxWaitTime = maxWaitMillis;
        initializePool();
    }
    
    /**
     * 获取连接 - 支持超时和中断
     */
    public Connection getConnection() throws InterruptedException, TimeoutException {
        lock.lock();
        try {
            long endTime = System.currentTimeMillis() + maxWaitTime;
            
            while (pool.isEmpty()) {
                long remainingTime = endTime - System.currentTimeMillis();
                if (remainingTime <= 0) {
                    throw new TimeoutException("获取连接超时");
                }
                
                // 等待连接可用,支持超时
                if (!notEmpty.await(remainingTime, TimeUnit.MILLISECONDS)) {
                    throw new TimeoutException("获取连接超时");
                }
            }
            
            // 获取并验证连接
            Connection conn = pool.removeFirst();
            if (!isConnectionValid(conn)) {
                conn = createNewConnection();
            }
            return conn;
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 归还连接
     */
    public void returnConnection(Connection conn) {
        if (conn == null) return;
        
        lock.lock();
        try {
            if (pool.size() < maxSize && isConnectionValid(conn)) {
                pool.addLast(conn);
                notEmpty.signal();  // 通知等待的线程
            } else {
                // 连接池已满或连接无效,关闭连接
                closeConnection(conn);
            }
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 尝试获取连接(非阻塞)
     */
    public Connection tryGetConnection() {
        if (lock.tryLock()) {
            try {
                if (!pool.isEmpty()) {
                    Connection conn = pool.removeFirst();
                    if (isConnectionValid(conn)) {
                        return conn;
                    }
                }
            } finally {
                lock.unlock();
            }
        }
        return null;
    }
    
    private boolean isConnectionValid(Connection conn) {
        // 连接有效性检查逻辑
        try {
            return conn != null && !conn.isClosed() && conn.isValid(2);
        } catch (SQLException e) {
            return false;
        }
    }
    
    private Connection createNewConnection() {
        // 创建新连接的逻辑
        return null; // 简化实现
    }
    
    private void closeConnection(Connection conn) {
        // 关闭连接的逻辑
    }
    
    private void initializePool() {
        // 初始化连接池
        for (int i = 0; i < maxSize / 2; i++) {
            pool.add(createNewConnection());
        }
    }
}

8.2.2 读写锁最佳实践:配置中心

/**
 * 基于读写锁的配置中心
 * 特性:高频读取,低频更新,保证数据一致性
 */
public class ConfigurationCenter {
    private final Map<String, String> configs = new HashMap<>();
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();
    
    /**
     * 获取配置 - 高频操作,使用读锁
     */
    public String getConfig(String key) {
        readLock.lock();
        try {
            String value = configs.get(key);
            // 模拟配置读取的耗时操作
            simulateProcess(1);
            return value;
        } finally {
            readLock.unlock();
        }
    }
    
    /**
     * 批量获取配置 - 读锁支持并发
     */
    public Map<String, String> getConfigs(Set<String> keys) {
        readLock.lock();
        try {
            Map<String, String> result = new HashMap<>();
            for (String key : keys) {
                result.put(key, configs.get(key));
            }
            simulateProcess(keys.size());
            return result;
        } finally {
            readLock.unlock();
        }
    }
    
    /**
     * 更新配置 - 低频操作,使用写锁
     */
    public void updateConfig(String key, String value) {
        writeLock.lock();
        try {
            // 模拟配置更新的耗时操作
            simulateProcess(10);
            configs.put(key, value);
            System.out.println("配置更新: " + key + " = " + value);
        } finally {
            writeLock.unlock();
        }
    }
    
    /**
     * 批量更新配置 - 写锁保证原子性
     */
    public void updateConfigs(Map<String, String> newConfigs) {
        writeLock.lock();
        try {
            simulateProcess(newConfigs.size() * 5);
            configs.putAll(newConfigs);
            System.out.println("批量更新配置: " + newConfigs.size() + " 项");
        } finally {
            writeLock.unlock();
        }
    }
    
    /**
     * 热更新配置 - 使用锁降级保证数据一致性
     */
    public void hotUpdateConfig(String key, String value) {
        // 先获取写锁进行更新
        writeLock.lock();
        try {
            // 更新配置
            configs.put(key, value);
            System.out.println("热更新配置: " + key + " = " + value);
            
            // 锁降级:在释放写锁前获取读锁
            readLock.lock();
        } finally {
            writeLock.unlock();  // 锁降级完成
        }
        
        try {
            // 在读锁保护下进行后续操作(如通知观察者、记录日志等)
            notifyConfigChange(key, value);
            logConfigChange(key, value);
        } finally {
            readLock.unlock();
        }
    }
    
    private void notifyConfigChange(String key, String value) {
        // 通知配置变更观察者
        simulateProcess(2);
    }
    
    private void logConfigChange(String key, String value) {
        // 记录配置变更日志
        simulateProcess(1);
    }
    
    private void simulateProcess(int milliseconds) {
        try {
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

8.2.3 Condition最佳实践:任务调度器

/**
 * 基于Condition的任务调度器
 * 特性:支持任务等待、超时控制、优雅关闭
 */
public class TaskScheduler {
    private final PriorityBlockingQueue<Task> taskQueue = new PriorityBlockingQueue<>();
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition taskAvailable = lock.newCondition();
    private final Condition schedulerStopped = lock.newCondition();
    private volatile boolean running = true;
    private final Thread workerThread;
    
    public TaskScheduler() {
        this.workerThread = new Thread(this::processTasks, "TaskScheduler-Worker");
        this.workerThread.start();
    }
    
    /**
     * 提交任务 - 支持超时
     */
    public boolean submitTask(Task task, long timeout, TimeUnit unit) 
            throws InterruptedException {
        lock.lock();
        try {
            long deadline = System.nanoTime() + unit.toNanos(timeout);
            
            // 等待直到有空间或超时
            while (taskQueue.size() >= 1000) {  // 队列容量限制
                long remaining = deadline - System.nanoTime();
                if (remaining <= 0) {
                    return false;  // 超时
                }
                if (!taskAvailable.await(remaining, TimeUnit.NANOSECONDS)) {
                    return false;  // 超时
                }
            }
            
            taskQueue.offer(task);
            taskAvailable.signal();  // 通知工作线程
            return true;
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 立即提交任务(非阻塞)
     */
    public boolean submitTaskNow(Task task) {
        lock.lock();
        try {
            if (taskQueue.size() >= 1000) {
                return false;  // 队列已满
            }
            taskQueue.offer(task);
            taskAvailable.signal();
            return true;
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 优雅关闭 - 等待所有任务完成
     */
    public void shutdown() throws InterruptedException {
        lock.lock();
        try {
            running = false;
            taskAvailable.signalAll();  // 唤醒工作线程
            
            // 等待任务队列清空
            while (!taskQueue.isEmpty()) {
                schedulerStopped.await(1, TimeUnit.SECONDS);
            }
        } finally {
            lock.unlock();
        }
        
        workerThread.join();
    }
    
    /**
     * 立即关闭
     */
    public void shutdownNow() {
        lock.lock();
        try {
            running = false;
            taskQueue.clear();
            taskAvailable.signalAll();
        } finally {
            lock.unlock();
        }
    }
    
    private void processTasks() {
        while (running || !taskQueue.isEmpty()) {
            try {
                Task task = taskQueue.poll(1, TimeUnit.SECONDS);
                if (task != null) {
                    executeTask(task);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        
        // 通知关闭完成
        lock.lock();
        try {
            schedulerStopped.signalAll();
        } finally {
            lock.unlock();
        }
    }
    
    private void executeTask(Task task) {
        try {
            task.execute();
        } catch (Exception e) {
            System.err.println("任务执行失败: " + e.getMessage());
        }
    }
    
    public static class Task implements Comparable<Task> {
        private final Runnable runnable;
        private final long scheduledTime;
        private final int priority;
        
        public Task(Runnable runnable, long delay, TimeUnit unit, int priority) {
            this.runnable = runnable;
            this.scheduledTime = System.nanoTime() + unit.toNanos(delay);
            this.priority = priority;
        }
        
        public void execute() {
            runnable.run();
        }
        
        @Override
        public int compareTo(Task other) {
            int timeCompare = Long.compare(this.scheduledTime, other.scheduledTime);
            if (timeCompare != 0) {
                return timeCompare;
            }
            return Integer.compare(other.priority, this.priority);  // 优先级高的在前
        }
    }
}

8.2.4 LockSupport最佳实践:自定义同步器

/**
 * 基于LockSupport的自定义闭锁
 * 特性:一次性屏障,支持超时和中断
 */
public class SimpleCountDownLatch {
    private volatile int count;
    private final Queue<Thread> waiters = new ConcurrentLinkedQueue<>();
    
    public SimpleCountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("计数不能为负");
        this.count = count;
    }
    
    /**
     * 等待闭锁打开
     */
    public void await() throws InterruptedException {
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        
        if (count <= 0) {
            return;  // 已经打开
        }
        
        // 使用LockSupport阻塞
        Thread current = Thread.currentThread();
        waiters.offer(current);
        
        // 双重检查避免错过信号
        if (count > 0) {
            LockSupport.park(this);
        }
        
        // 检查是否被中断唤醒
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
    }
    
    /**
     * 超时等待
     */
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        
        if (count <= 0) {
            return true;
        }
        
        long deadline = System.nanoTime() + unit.toNanos(timeout);
        Thread current = Thread.currentThread();
        waiters.offer(current);
        
        try {
            while (count > 0) {
                long remaining = deadline - System.nanoTime();
                if (remaining <= 0) {
                    return false;  // 超时
                }
                LockSupport.parkNanos(this, remaining);
                
                if (Thread.interrupted()) {
                    throw new InterruptedException();
                }
            }
            return true;
        } finally {
            waiters.remove(current);
        }
    }
    
    /**
     * 计数减1
     */
    public void countDown() {
        if (count <= 0) {
            return;  // 已经打开
        }
        
        if (--count == 0) {
            // 唤醒所有等待线程
            Thread waiter;
            while ((waiter = waiters.poll()) != null) {
                LockSupport.unpark(waiter);
            }
        }
    }
    
    /**
     * 获取当前计数
     */
    public int getCount() {
        return count;
    }
}

8.3 性能优化和陷阱避免

8.3.1 锁性能优化技巧

/**
 * 锁性能优化实践
 */
public class LockPerformanceOptimization {
    private final ReentrantLock lock = new ReentrantLock();
    private int counter = 0;
    private long lastLogTime = System.currentTimeMillis();
    
    // ❌ 锁粒度太粗
    public void coarseGrainedLock() {
        lock.lock();
        try {
            // 包含非临界区操作
            loadFromDatabase();  // 耗时IO操作
            counter++;           // 真正的临界区
            saveToDatabase();    // 耗时IO操作
        } finally {
            lock.unlock();
        }
    }
    
    // ✅ 锁粒度细化
    public void fineGrainedLock() {
        // 在锁外执行IO操作
        loadFromDatabase();
        
        lock.lock();
        try {
            counter++;  // 只保护真正的临界区
        } finally {
            lock.unlock();
        }
        
        saveToDatabase();  // 在锁外执行IO操作
    }
    
    // ✅ 使用原子变量替代锁
    private final AtomicInteger atomicCounter = new AtomicInteger(0);
    
    public void atomicOperation() {
        atomicCounter.incrementAndGet();  // 无锁操作,性能更高
    }
    
    // ✅ 读写分离
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();
    private volatile boolean initialized = false;
    
    public void lazyInit() {
        if (!initialized) {
            writeLock.lock();
            try {
                // 双重检查
                if (!initialized) {
                    performInitialization();
                    initialized = true;
                }
            } finally {
                writeLock.unlock();
            }
        }
        
        // 后续读操作使用读锁
        readLock.lock();
        try {
            useInitializedResource();
        } finally {
            readLock.unlock();
        }
    }
    
    private void loadFromDatabase() {
        // 模拟数据库加载
    }
    
    private void saveToDatabase() {
        // 模拟数据库保存
    }
    
    private void performInitialization() {
        // 初始化操作
    }
    
    private void useInitializedResource() {
        // 使用初始化后的资源
    }
}

8.3.2 常见陷阱及避免方法

/**
 * 并发编程常见陷阱及解决方案
 */
public class ConcurrentPitfalls {
    
    // 陷阱1:在锁内调用外部方法(可能发生死锁)
    public void trap1() {
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        try {
            externalMethod();  // 危险!可能获取其他锁
        } finally {
            lock.unlock();
        }
    }
    
    // 解决方案:减少锁内代码,只包含必要的临界区操作
    public void solution1() {
        ReentrantLock lock = new ReentrantLock();
        // 在锁外准备数据
        Object data = prepareData();
        
        lock.lock();
        try {
            // 只执行必须同步的操作
            updateSharedState(data);
        } finally {
            lock.unlock();
        }
    }
    
    // 陷阱2:忘记在finally中释放锁
    public void trap2() {
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        if (someCondition()) {
            return;  // 忘记释放锁!
        }
        lock.unlock();
    }
    
    // 解决方案:使用try-finally模板
    public void solution2() {
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        try {
            if (someCondition()) {
                return;
            }
            // 其他操作
        } finally {
            lock.unlock();  // 确保释放
        }
    }
    
    // 陷阱3:在Condition.await()中使用if而不是while
    public void trap3() throws InterruptedException {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        boolean conditionMet = false;
        
        lock.lock();
        try {
            if (!conditionMet) {  // 错误!应该用while
                condition.await();
            }
            // 可能被虚假唤醒,条件仍未满足
        } finally {
            lock.unlock();
        }
    }
    
    // 解决方案:总是使用while循环检查条件
    public void solution3() throws InterruptedException {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        boolean conditionMet = false;
        
        lock.lock();
        try {
            while (!conditionMet) {  // 正确!防止虚假唤醒
                condition.await();
            }
            // 条件确定满足
        } finally {
            lock.unlock();
        }
    }
    
    private boolean someCondition() {
        return Math.random() > 0.5;
    }
    
    private Object prepareData() {
        return new Object();
    }
    
    private void updateSharedState(Object data) {
        // 更新共享状态
    }
    
    private void externalMethod() {
        // 可能获取其他锁的外部方法
    }
}

8.4 监控和调试技巧

8.4.1 锁监控工具

/**
 * 锁监控和诊断工具
 */
public class LockMonitor {
    
    /**
     * 监控锁竞争情况
     */
    public static void monitorLockContention(ReentrantLock lock, String lockName) {
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(5000);  // 每5秒检查一次
                    
                    System.out.printf("锁[%s]监控: %n", lockName);
                    System.out.printf("  - 等待队列长度: %d%n", lock.getQueueLength());
                    System.out.printf("  - 是否有等待线程: %b%n", lock.hasQueuedThreads());
                    System.out.printf("  - 是否被当前线程持有: %b%n", lock.isHeldByCurrentThread());
                    System.out.printf("  - 重入次数: %d%n", lock.getHoldCount());
                    
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }, "LockMonitor-" + lockName).start();
    }
    
    /**
     * 死锁检测
     */
    public static void detectDeadlock() {
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        long[] threadIds = threadMXBean.findDeadlockedThreads();
        
        if (threadIds != null) {
            System.err.println("检测到死锁!");
            ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(threadIds);
            
            for (ThreadInfo threadInfo : threadInfos) {
                System.err.println("死锁线程: " + threadInfo.getThreadName());
                System.err.println("阻塞对象: " + threadInfo.getLockName());
                System.err.println("阻塞者: " + threadInfo.getLockOwnerName());
            }
        }
    }
    
    /**
     * 锁性能统计
     */
    public static class LockStats {
        private final ReentrantLock lock;
        private long lockAcquireCount = 0;
        private long totalWaitTime = 0;
        private long maxWaitTime = 0;
        
        public LockStats(ReentrantLock lock) {
            this.lock = lock;
        }
        
        public void recordLockAcquire(long waitTime) {
            lockAcquireCount++;
            totalWaitTime += waitTime;
            maxWaitTime = Math.max(maxWaitTime, waitTime);
        }
        
        public void printStats() {
            System.out.printf("锁统计: %n");
            System.out.printf("  - 获取次数: %d%n", lockAcquireCount);
            System.out.printf("  - 平均等待时间: %.2fms%n", 
                lockAcquireCount > 0 ? (double)totalWaitTime / lockAcquireCount : 0);
            System.out.printf("  - 最大等待时间: %dms%n", maxWaitTime);
            System.out.printf("  - 当前等待线程: %d%n", lock.getQueueLength());
        }
    }
}

总结:正确使用并发锁的黄金法则

  1. 明确性:清楚知道每个锁保护的是什么数据
  2. 最小化:锁粒度尽可能小,持有时间尽可能短
  3. 一致性:按照固定顺序获取多个锁
  4. 可靠性:总是在finally块中释放锁
  5. 可中断性:对长时间操作使用可中断的锁获取方式
  6. 监控性:对关键锁进行监控和统计

Java并发包中的锁机制通过精妙的设计实现了高效、灵活的线程同步:

  • AQS是基石:提供了同步队列管理和状态控制的基础设施
  • Lock接口是门面:定义了丰富的锁操作API
  • 重入锁解决重入问题:支持同一线程多次获取锁
  • 读写锁优化读多写少场景:通过锁分离提升并发性能
  • LockSupport提供底层阻塞能力:线程控制的精准工具
  • Condition实现精确线程协调:多条件等待队列支持复杂同步逻辑

记住这个核心关系:Lock → AQS → Condition → LockSupport,它们共同构成了Java并发锁机制的完整体系。理解这些组件的内部机制,能够帮助我们正确选择和使用合适的同步工具,诊断和解决复杂的并发问题,设计高性能的并发组件。

记住这些原则和最佳实践,你就能构建出高效、可靠的并发程序。并发编程虽然复杂,但通过正确的工具和方法,完全可以驾驭!

posted @ 2025-10-29 08:42  佛祖让我来巡山  阅读(23)  评论(0)    收藏  举报

佛祖让我来巡山博客站 - 创建于 2018-08-15

开发工程师个人站,内容主要是网站开发方面的技术文章,大部分来自学习或工作,部分来源于网络,希望对大家有所帮助。

Bootstrap中文网