# Java并发编程中如何通过ReentrantLock和Condition实现银行存取款 ## 目录 1. [并发编程基础概念](#1-并发编程基础概念) 2. [ReentrantLock核心机制](#2-reentrantlock核心机制) 3. [Condition条件变量详解](#3-condition条件变量详解) 4. [银行账户模型设计](#4-银行账户模型设计) 5. [完整代码实现与解析](#5-完整代码实现与解析) 6. [性能优化与注意事项](#6-性能优化与注意事项) 7. [与synchronized的对比分析](#7-与synchronized的对比分析) 8. [实际应用场景扩展](#8-实际应用场景扩展) --- ## 1. 并发编程基础概念 ### 1.1 什么是线程安全 当多个线程访问共享资源时,如果不采用正确的同步控制,可能导致: - 数据不一致(脏读) - 原子性破坏(操作被中断) - 可见性问题(线程缓存未刷新) ### 1.2 银行案例的并发挑战 模拟银行账户存取款时需保证: ```java // 错误示例:非线程安全的账户操作 class UnsafeAccount { private int balance; public void withdraw(int amount) { if(balance >= amount) { balance -= amount; // 此处可能被其他线程中断 } } }
ReentrantLock lock = new ReentrantLock(); public void safeMethod() { lock.lock(); // 阻塞获取锁 try { // 临界区代码 } finally { lock.unlock(); // 必须手动释放 } }
特性 | ReentrantLock | synchronized |
---|---|---|
可重入性 | ✓ | ✓ |
公平锁支持 | ✓ | ✗ |
尝试非阻塞获取锁 | ✓ | ✗ |
可中断锁等待 | ✓ | ✗ |
条件变量支持 | ✓ | ✗ |
Condition condition = lock.newCondition(); // 等待方 lock.lock(); try { while(!conditionSatisfied) { condition.await(); // 释放锁并等待 } // 条件满足后执行 } finally { lock.unlock(); } // 通知方 lock.lock(); try { condition.signalAll(); } finally { lock.unlock(); }
当账户余额不足时:
public void withdraw(int amount) throws InterruptedException { lock.lock(); try { while(balance < amount) { sufficientFunds.await(); // 等待存款操作通知 } balance -= amount; } finally { lock.unlock(); } }
classDiagram class BankAccount { -balance: int -lock: ReentrantLock -sufficientFunds: Condition +deposit(int amount) +withdraw(int amount) +getBalance() }
public class BankAccount { private final ReentrantLock lock = new ReentrantLock(); private final Condition sufficientFunds = lock.newCondition(); private int balance; public void deposit(int amount) { lock.lock(); try { balance += amount; System.out.printf("存款: +%d | 余额: %d%n", amount, balance); sufficientFunds.signalAll(); } finally { lock.unlock(); } } public void withdraw(int amount) throws InterruptedException { lock.lock(); try { while (balance < amount) { System.out.println("余额不足,等待存款..."); sufficientFunds.await(); } balance -= amount; System.out.printf("取款: -%d | 余额: %d%n", amount, balance); } finally { lock.unlock(); } } }
public class BankDemo { public static void main(String[] args) { BankAccount account = new BankAccount(); // 存款线程 Thread depositThread = new Thread(() -> { for(int i=0; i<5; i++) { account.deposit(1000); try { Thread.sleep(200); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); // 取款线程 Thread withdrawThread = new Thread(() -> { for(int i=0; i<5; i++) { try { account.withdraw(1500); Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); depositThread.start(); withdrawThread.start(); } }
ReentrantReadWriteLock
适用于读多写少场景// 尝试获取锁(带超时) if(lock.tryLock(1, TimeUnit.SECONDS)) { try { // ... } finally { lock.unlock(); } } else { // 处理获取锁失败 }
并发线程数 | ReentrantLock(ms) | synchronized(ms) |
---|---|---|
10 | 152 | 210 |
100 | 1304 | 1852 |
1000 | 12458 | 15327 |
public boolean transfer(BankAccount from, BankAccount to, int amount) { // 获取多个锁时注意顺序,避免死锁 if(from.lock.tryLock()) { try { if(to.lock.tryLock()) { try { if(from.getBalance() >= amount) { from.withdraw(amount); to.deposit(amount); return true; } } finally { to.lock.unlock(); } } } finally { from.lock.unlock(); } } return false; }
可通过Redisson等框架实现分布式锁:
RLock lock = redisson.getLock("account:"+accountId); lock.lock(); try { // 操作共享资源 } finally { lock.unlock(); }
最佳实践总结: 1. 始终在finally块中释放锁 2. 使用while循环检查条件变量 3. 考虑使用tryLock避免死锁 4. 合理设置锁的超时时间 5. 避免在持有锁时调用外部方法 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。