18.3.4 ReentrantLock与synchronized区别

1. 基础概念对比

1.1 ReentrantLock简介

public class ReentrantLockBasics {
    
    private final ReentrantLock lock = new ReentrantLock();
    private int counter = 0;
    
    // ReentrantLock基本用法
    public void increment() {
        lock.lock(); // 获取锁
        try {
            counter++;
            System.out.println("Counter: " + counter + ", Thread: " + Thread.currentThread().getName());
        } finally {
            lock.unlock(); // 释放锁(必须在finally中)
        }
    }
    
    // 尝试获取锁
    public boolean tryIncrement() {
        if (lock.tryLock()) { // 尝试获取锁,不阻塞
            try {
                counter++;
                return true;
            } finally {
                lock.unlock();
            }
        }
        return false;
    }
    
    // 超时获取锁
    public boolean incrementWithTimeout(long timeout, TimeUnit unit) {
        try {
            if (lock.tryLock(timeout, unit)) { // 带超时的尝试获取锁
                try {
                    counter++;
                    return true;
                } finally {
                    lock.unlock();
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return false;
    }
    
    public int getCounter() {
        return counter;
    }
}

1.2 synchronized基本用法回顾

public class SynchronizedBasics {
    
    private int counter = 0;
    
    // synchronized方法
    public synchronized void increment() {
        counter++;
        System.out.println("Counter: " + counter + ", Thread: " + Thread.currentThread().getName());
    }
    
    // synchronized代码块
    public void incrementBlock() {
        synchronized (this) {
            counter++;
        }
    }
    
    // 静态synchronized方法
    public static synchronized void staticMethod() {
        System.out.println("静态同步方法");
    }
    
    public int getCounter() {
        synchronized (this) {
            return counter;
        }
    }
}

2. 核心区别对比

2.1 功能特性对比

锁的实现

API层面的互斥锁

JVM层面的内置锁

可重入性

支持

支持

公平性

支持公平锁和非公平锁

非公平锁

中断响应

支持中断

不支持中断

超时机制

支持超时获取锁

不支持

条件变量

支持多个Condition

只有一个wait/notify

锁状态查询

可查询锁状态

无法查询

性能

高并发下性能更好

JVM优化后性能接近

2.2 详细功能对比演示

public class FeatureComparison {
    
    private final ReentrantLock reentrantLock = new ReentrantLock(true); // 公平锁
    private final Object synchronizedLock = new Object();
    
    // 1. 公平性对比
    public void demonstrateFairness() {
        System.out.println("=== 公平性对比演示 ===");
        
        // ReentrantLock公平锁
        ExecutorService executor = Executors.newFixedThreadPool(5);
        
        for (int i = 0; i < 5; i++) {
            final int threadId = i;
            executor.submit(() -> {
                for (int j = 0; j < 3; j++) {
                    reentrantLock.lock();
                    try {
                        System.out.println("公平锁 - 线程" + threadId + "获得锁,执行第" + (j + 1) + "次");
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    } finally {
                        reentrantLock.unlock();
                    }
                }
            });
        }
        
        executor.shutdown();
        try {
            executor.awaitTermination(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        // synchronized(非公平)
        ExecutorService executor2 = Executors.newFixedThreadPool(5);
        
        for (int i = 0; i < 5; i++) {
            final int threadId = i;
            executor2.submit(() -> {
                for (int j = 0; j < 3; j++) {
                    synchronized (synchronizedLock) {
                        System.out.println("synchronized - 线程" + threadId + "获得锁,执行第" + (j + 1) + "次");
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                }
            });
        }
        
        executor2.shutdown();
    }
    
    // 2. 中断响应对比
    public void demonstrateInterruptibility() {
        System.out.println("=== 中断响应对比演示 ===");
        
        // ReentrantLock支持中断
        Thread lockThread = new Thread(() -> {
            try {
                System.out.println("ReentrantLock线程尝试获取锁...");
                reentrantLock.lockInterruptibly(); // 可中断的锁获取
                try {
                    System.out.println("ReentrantLock线程获得锁");
                    Thread.sleep(5000);
                } finally {
                    reentrantLock.unlock();
                }
            } catch (InterruptedException e) {
                System.out.println("ReentrantLock线程被中断");
            }
        });
        
        Thread interruptThread = new Thread(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("中断ReentrantLock线程");
                lockThread.interrupt();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        lockThread.start();
        interruptThread.start();
        
        try {
            lockThread.join();
            interruptThread.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        // synchronized不支持中断(演示)
        Thread syncThread = new Thread(() -> {
            synchronized (synchronizedLock) {
                System.out.println("synchronized线程获得锁,开始长时间操作");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    System.out.println("synchronized线程被中断,但仍持有锁");
                }
            }
        });
        
        syncThread.start();
    }
    
    // 3. 超时机制对比
    public void demonstrateTimeout() {
        System.out.println("=== 超时机制对比演示 ===");
        
        // ReentrantLock支持超时
        Thread holderThread = new Thread(() -> {
            reentrantLock.lock();
            try {
                System.out.println("持有锁的线程开始长时间操作");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                reentrantLock.unlock();
            }
        });
        
        Thread timeoutThread = new Thread(() -> {
            try {
                System.out.println("尝试在2秒内获取锁...");
                if (reentrantLock.tryLock(2, TimeUnit.SECONDS)) {
                    try {
                        System.out.println("成功获取锁");
                    } finally {
                        reentrantLock.unlock();
                    }
                } else {
                    System.out.println("获取锁超时");
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        holderThread.start();
        try {
            Thread.sleep(1000); // 确保holderThread先获取锁
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        timeoutThread.start();
    }
}

3. 条件变量对比

3.1 ReentrantLock的Condition

public class ConditionExample {
    
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();
    private final Condition notFull = lock.newCondition();
    
    private final Queue<Integer> queue = new LinkedList<>();
    private final int capacity = 5;
    
    // 生产者
    public void produce(int item) throws InterruptedException {
        lock.lock();
        try {
            while (queue.size() == capacity) {
                System.out.println("队列已满,生产者等待");
                notFull.await(); // 等待队列不满
            }
            
            queue.offer(item);
            System.out.println("生产: " + item + ", 队列大小: " + queue.size());
            notEmpty.signal(); // 通知消费者队列不空
            
        } finally {
            lock.unlock();
        }
    }
    
    // 消费者
    public int consume() throws InterruptedException {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                System.out.println("队列为空,消费者等待");
                notEmpty.await(); // 等待队列不空
            }
            
            int item = queue.poll();
            System.out.println("消费: " + item + ", 队列大小: " + queue.size());
            notFull.signal(); // 通知生产者队列不满
            
            return item;
            
        } finally {
            lock.unlock();
        }
    }
    
    public void demonstrateCondition() {
        // 创建生产者线程
        Thread producer = new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    produce(i);
                    Thread.sleep(200);
                }
            } catch (InterruptedExcepti

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java面试圣经 文章被收录于专栏

Java面试圣经,带你练透java圣经

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务