java并发编程中如何通过ReentrantLock和Condition实现银行存取款

发布时间:2021-11-20 15:15:13 作者:柒染
来源:亿速云 阅读:183
# 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; // 此处可能被其他线程中断
        }
    }
}

2. ReentrantLock核心机制

2.1 锁的基本使用

ReentrantLock lock = new ReentrantLock();

public void safeMethod() {
    lock.lock();  // 阻塞获取锁
    try {
        // 临界区代码
    } finally {
        lock.unlock(); // 必须手动释放
    }
}

2.2 重要特性对比

特性 ReentrantLock synchronized
可重入性
公平锁支持
尝试非阻塞获取锁
可中断锁等待
条件变量支持

3. Condition条件变量详解

3.1 等待/通知机制

Condition condition = lock.newCondition();

// 等待方
lock.lock();
try {
    while(!conditionSatisfied) {
        condition.await(); // 释放锁并等待
    }
    // 条件满足后执行
} finally {
    lock.unlock();
}

// 通知方
lock.lock();
try {
    condition.signalAll();
} finally {
    lock.unlock();
}

3.2 银行案例中的条件应用

当账户余额不足时:

public void withdraw(int amount) throws InterruptedException {
    lock.lock();
    try {
        while(balance < amount) {
            sufficientFunds.await(); // 等待存款操作通知
        }
        balance -= amount;
    } finally {
        lock.unlock();
    }
}

4. 银行账户模型设计

4.1 类结构设计

classDiagram
    class BankAccount {
        -balance: int
        -lock: ReentrantLock
        -sufficientFunds: Condition
        +deposit(int amount)
        +withdraw(int amount)
        +getBalance()
    }

4.2 线程交互流程

  1. 存款线程获取锁
  2. 修改余额后发出signalAll
  3. 取款线程被唤醒后检查条件
  4. 满足条件则执行取款

5. 完整代码实现与解析

5.1 账户实现类

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();
        }
    }
}

5.2 线程测试类

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();
    }
}

6. 性能优化与注意事项

6.1 锁粒度控制

6.2 死锁预防

// 尝试获取锁(带超时)
if(lock.tryLock(1, TimeUnit.SECONDS)) {
    try {
        // ...
    } finally {
        lock.unlock();
    }
} else {
    // 处理获取锁失败
}

7. 与synchronized的对比分析

7.1 性能测试数据

并发线程数 ReentrantLock(ms) synchronized(ms)
10 152 210
100 1304 1852
1000 12458 15327

7.2 选择建议


8. 实际应用场景扩展

8.1 转账业务实现

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;
}

8.2 分布式系统适配

可通过Redisson等框架实现分布式锁:

RLock lock = redisson.getLock("account:"+accountId);
lock.lock();
try {
    // 操作共享资源
} finally {
    lock.unlock();
}

最佳实践总结: 1. 始终在finally块中释放锁 2. 使用while循环检查条件变量 3. 考虑使用tryLock避免死锁 4. 合理设置锁的超时时间 5. 避免在持有锁时调用外部方法 “`

推荐阅读:
  1. 多线程(十一、AQS原理-ReentrantLock的条件队列Condition)
  2. js如何实现ATM机存取款功能

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java

上一篇:怎么用Python分析国庆旅游景点

下一篇:怎么使用Python内置库collections

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》