可重入锁案例

wen java案例 1

本文目录导读:

可重入锁案例

  1. 什么是可重入锁?
  2. 案例一:递归调用(最典型场景)
  3. 案例二:继承关系中的重入
  4. 案例三:ReentrantLock的高级特性
  5. 案例四:数据库连接池(实际应用)
  6. 案例五:性能对比和注意事项
  7. 常见问题解答

我来为你展示几个可重入锁的经典案例,从基础到进阶逐步深入。

什么是可重入锁?

可重入锁(Reentrant Lock)指的是:同一个线程可以多次获取同一个锁而不会发生死锁。

public class ReentrantDemo {
    public synchronized void methodA() {
        System.out.println("进入方法A");
        // 同一个线程可以再次获取锁
        methodB();  // 不会死锁,因为synchronized是可重入的
    }
    public synchronized void methodB() {
        System.out.println("进入方法B");
    }
    public static void main(String[] args) {
        ReentrantDemo demo = new ReentrantDemo();
        demo.methodA();  // 输出:进入方法A → 进入方法B
    }
}

案例一:递归调用(最典型场景)

public class RecursiveLockDemo {
    private int count = 0;
    // 使用synchronized实现可重入
    public synchronized void increment() {
        count++;
        System.out.println("当前值: " + count + ", 线程: " + Thread.currentThread().getName());
        if (count < 5) {
            increment();  // 递归调用,同一个线程再次进入
        }
    }
    // 使用ReentrantLock实现可重入
    private ReentrantLock lock = new ReentrantLock();
    public void incrementWithLock() {
        lock.lock();
        try {
            count++;
            System.out.println("Lock值: " + count + ", 持有锁次数: " + lock.getHoldCount());
            if (count < 3) {
                incrementWithLock();  // 递归调用
            }
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        RecursiveLockDemo demo = new RecursiveLockDemo();
        demo.increment();  // 输出1-5,不会死锁
    }
}

案例二:继承关系中的重入

public class InheritanceReentrantDemo {
    static class Parent {
        public synchronized void doSomething() {
            System.out.println("父类方法执行 - " + Thread.currentThread().getName());
        }
    }
    static class Child extends Parent {
        @Override
        public synchronized void doSomething() {
            System.out.println("子类方法执行 - " + Thread.currentThread().getName());
            // 调用父类方法,需要再次获取锁
            super.doSomething();  // 这是可重入的,不会死锁
        }
    }
    public static void main(String[] args) {
        Child child = new Child();
        child.doSomething();
    }
}

案例三:ReentrantLock的高级特性

import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockAdvancedDemo {
    // 公平锁:true表示公平锁
    private ReentrantLock fairLock = new ReentrantLock(true);
    // 非公平锁:默认
    private ReentrantLock nonFairLock = new ReentrantLock();
    public void demonstrateFeatures() throws InterruptedException {
        // 1. 可重入性验证
        fairLock.lock();
        try {
            System.out.println("第一次获取锁");
            System.out.println("锁持有次数: " + fairLock.getHoldCount());
            fairLock.lock();  // 再次获取
            try {
                System.out.println("第二次获取锁");
                System.out.println("锁持有次数: " + fairLock.getHoldCount());
            } finally {
                fairLock.unlock();
                System.out.println("释放一次,剩余持有次数: " + fairLock.getHoldCount());
            }
        } finally {
            fairLock.unlock();
            System.out.println("释放一次,剩余持有次数: " + fairLock.getHoldCount());
        }
        // 2. 可中断性
        Thread waitingThread = new Thread(() -> {
            try {
                nonFairLock.lockInterruptibly();
                try {
                    System.out.println("线程获取到锁");
                } finally {
                    nonFairLock.unlock();
                }
            } catch (InterruptedException e) {
                System.out.println("线程被中断,无法获取锁");
            }
        });
        waitingThread.start();
        Thread.sleep(100);
        waitingThread.interrupt();  // 中断等待的线程
        // 3. 尝试获取锁(非阻塞)
        if (nonFairLock.tryLock()) {
            try {
                System.out.println("成功获取锁");
            } finally {
                nonFairLock.unlock();
            }
        } else {
            System.out.println("锁被占用,操作失败");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        ReentrantLockAdvancedDemo demo = new ReentrantLockAdvancedDemo();
        demo.demonstrateFeatures();
    }
}

案例四:数据库连接池(实际应用)

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;
public class ConnectionPoolDemo {
    private static class Connection {
        private boolean inUse = false;
        public void use() {
            System.out.println("连接被使用 - " + Thread.currentThread().getName());
            // 模拟耗时操作
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
    private final Connection[] connections;
    private final boolean[] used;
    private final ReentrantLock lock = new ReentrantLock();
    private final java.util.concurrent.locks.Condition available = lock.newCondition();
    public ConnectionPoolDemo(int size) {
        connections = new Connection[size];
        used = new boolean[size];
        for (int i = 0; i < size; i++) {
            connections[i] = new Connection();
        }
    }
    public Connection getConnection() throws InterruptedException {
        lock.lock();
        try {
            while (true) {
                // 查找空闲连接
                for (int i = 0; i < connections.length; i++) {
                    if (!used[i]) {
                        used[i] = true;
                        System.out.println("获取连接 " + i + " - " + Thread.currentThread().getName());
                        return connections[i];
                    }
                }
                // 没有空闲连接,等待
                System.out.println("等待连接... - " + Thread.currentThread().getName());
                available.await(1, TimeUnit.SECONDS);
            }
        } finally {
            lock.unlock();
        }
    }
    public void returnConnection(Connection connection) {
        lock.lock();
        try {
            for (int i = 0; i < connections.length; i++) {
                if (connections[i] == connection && used[i]) {
                    used[i] = false;
                    System.out.println("归还连接 " + i + " - " + Thread.currentThread().getName());
                    available.signalAll();
                    return;
                }
            }
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        ConnectionPoolDemo pool = new ConnectionPoolDemo(2);
        // 模拟多个线程使用连接池
        for (int i = 0; i < 4; i++) {
            new Thread(() -> {
                try {
                    Connection conn = pool.getConnection();
                    conn.use();
                    pool.returnConnection(conn);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }, "线程-" + i).start();
        }
    }
}

案例五:性能对比和注意事项

public class PerformanceComparisonDemo {
    // 循环次数
    private static final int LOOPS = 1000000;
    // 使用synchronized
    private int syncCount = 0;
    // 使用ReentrantLock
    private int lockCount = 0;
    private final ReentrantLock lock = new ReentrantLock();
    public synchronized void incrementSync() {
        syncCount++;
    }
    public void incrementLock() {
        lock.lock();
        try {
            lockCount++;
        } finally {
            lock.unlock();
        }
    }
    public void comparePerformance() {
        // 测试synchronized
        long startTime = System.nanoTime();
        for (int i = 0; i < LOOPS; i++) {
            incrementSync();
        }
        long syncTime = System.nanoTime() - startTime;
        // 测试ReentrantLock
        long startTime2 = System.nanoTime();
        for (int i = 0; i < LOOPS; i++) {
            incrementLock();
        }
        long lockTime = System.nanoTime() - startTime2;
        System.out.println("synchronized耗时: " + syncTime / 1000000 + "ms");
        System.out.println("ReentrantLock耗时: " + lockTime / 1000000 + "ms");
    }
    public static void main(String[] args) {
        PerformanceComparisonDemo demo = new PerformanceComparisonDemo();
        demo.comparePerformance();
        // 注意事项示例
        System.out.println("\n=== 注意事项 ===");
        System.out.println("1. 必须成对使用lock/unlock,用try-finally保证");
        System.out.println("2. 不要忘了释放锁,否则会造成死锁");
        System.out.println("3. 尽量使用锁的作用域最小化");
        System.out.println("4. 考虑使用tryLock避免死锁");
    }
}

常见问题解答

public class CommonQuestionsDemo {
    // Q1: synchronized和ReentrantLock的区别?
    public static void question1() {
        System.out.println("=== 区别 ===");
        System.out.println("1. synchronized是JVM层面,ReentrantLock是JDK层面");
        System.out.println("2. ReentrantLock支持中断、超时、公平锁");
        System.out.println("3. ReentrantLock需要手动释放锁");
        System.out.println("4. synchronized会自动释放锁");
    }
    // Q2: 什么情况下会发生死锁?
    public static void question2() {
        Object lockA = new Object();
        Object lockB = new Object();
        // 死锁示例
        Thread thread1 = new Thread(() -> {
            synchronized (lockA) {
                System.out.println("线程1持有锁A");
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                synchronized (lockB) {
                    System.out.println("线程1持有锁B");
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            synchronized (lockB) {
                System.out.println("线程2持有锁B");
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                synchronized (lockA) {
                    System.out.println("线程2持有锁A");
                }
            }
        });
        System.out.println("=== 这会产生死锁,因为线程互相等待对方持有的锁 ===");
        System.out.println("解决方式:\n1. 按顺序获取锁\n2. 使用tryLock设置超时\n3. 使用Lock-free数据结构");
    }
    public static void main(String[] args) {
        question1();
        System.out.println();
        question2();
    }
}
  1. 可重入锁的本质:同一线程可以多次获取同一个锁,通过计数器记录持有次数
  2. 两种实现方式synchronized关键字和ReentrantLock
  3. 主要应用场景:递归调用、方法嵌套、继承中的锁传递
  4. ReentrantLock优势:提供更多特性(可中断、可超时、公平锁等)
  5. 使用注意事项:必须成对使用lock/unlock,确保释放锁

这些案例涵盖了可重入锁的主要使用场景,从简单的递归到实际的项目应用,希望能帮助你深入理解可重入锁的机制和用法。

抱歉,评论功能暂时关闭!