开发者

Java并发编程之Lock锁机制从使用到源码实现

目录
  • 1. 锁的基本概念:从现实世界到代码世界
    • 1.1 锁的演进:synchronized → Lock
    • 1.2 Lock接口的核心优势
  • 2. AQS:并发世界的交通指挥中心
    • 2.1 AQS的核心设计思想
    • 2.2 同步队列:线程的"等候区"
    • 2.3 自定义锁实战:基于AQS实现TwinsLock
  • 3. 重入锁ReentrantLock:可重复使用的智能锁
    • 3.1 重入性:一把钥匙开多把锁
    • 3.2 公平锁 vs 非公平锁
    • 3.3 重入锁实现原理
  • 4. 读写锁ReentrantReadwriteLock:读写分离的高并发锁
    • 4.1 读写锁的应用场景
    • 4.2 读写锁的状态设计
    • 4.3 锁降级:保证数据可见性的重要技术
  • 5. LockSupport:线程的精准遥控器
    • 5.1 LockSupport的核心能力
    • 5.2 许可机制:先发后至的灵活性
    • 5.3 blocker:线程诊断的"身份证"
  • 6. Condition接口:精准的线程协调器
    • 6.1 Condition vs Object监视器
    • 6.2 Condition实战:有界阻塞队列
    • 6.3 Condition内部机制:等待队列与同步队列的协作
  • 7. AQS同步队列 vs Condition等待队列
    • 7.1 核心区别总结
    • 7.2 队列协作的完整示例
  • 8. 实战指南:如何正确使用Java并发锁
    • 8.1 锁使用的核心原则
    • 原则1:永远在finally块中释放锁
    • 原则2:避免锁嵌套,预防死锁
    • 8.2 各组件最佳实践案例
      • 8.2.1 ReentrantLock最佳实践:连接池管理
      • 8.2.2 读写锁最佳实践:配置中心
      • 8.2.3 Condition最佳实践:任务调度器
      • 8.2.4 LockSupport最佳实践:自定义同步器
    • 8.3 性能优化和陷阱避免
      • 8.3.1 锁性能优化技巧
      • 8.3.2 常见陷阱及避免方法
    • 8.4 监控和调试技巧
      • 8.4.1 锁监控工具
  • 总结:正确使用并发锁的黄金法则

    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接口的核心优势

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

    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();  // 锁降级开始
    qKiqanVwYY            } 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/notifyCondition.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, PROPAGATECONDITION(-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();
            }
        }
        /**
         * 尝试获取连接(非阻塞)android
         */
        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.p编程utAll(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 updateSharpythonedState(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());
            }
        }
    }

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

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

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

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

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

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

    到此这篇关于Java并发编程之Lock锁机制从使用到源码实现的文章就介绍到这了,更多相关Java Lock锁机制内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜