
本文深入探讨了在 Java 中实现多线程共享银行账户同步的机制。通过一个实际案例,详细阐述了如何利用 `synchronized` 关键字以及 `wait()` 和 `notifyAll()` 方法来解决并发存取问题,确保账户余额在多个线程同时操作时保持一致性,并严格遵守最小/最大余额限制,从而避免竞态条件和数据不一致。
在并发编程中,当多个线程需要访问和修改同一个共享资源时,如果不采取适当的同步机制,就可能导致数据不一致、竞态条件甚至死锁。银行账户系统就是一个典型的共享资源场景:多个人(线程)可能同时尝试对同一个账户进行存款或取款操作。为了确保账户余额的准确性并遵守业务规则(如最小/最大余额限制),我们必须引入线程同步。
本教程将通过一个 Java 银行账户同步的案例,详细讲解如何使用 synchronized 关键字以及 Object 类的 wait() 和 notifyAll() 方法来构建一个健壮的并发控制系统。
在深入案例之前,我们先回顾 Java 中用于线程协作的关键机制:
立即学习“Java免费学习笔记(深入)”;
synchronized 关键字:
Object.wait() 方法:
Object.notify() 和 Object.notifyAll() 方法:
重要提示:wait(), notify(), `notifyAll() 必须在持有对象监视器(即 synchronized 锁)的情况下调用,否则会抛出 IllegalMonitorStateException。
假设我们有一个银行账户 Cuenta,由两个 Persona(人)共享。账户有最大存款限制 500 欧元和最小余额限制 1 欧元。Persona 线程会不断尝试存款和取款。如果操作因为余额限制无法进行,线程应等待其他线程改变账户状态,然后继续尝试。
我们将创建三个类:
Cuenta 类是共享资源,其 ingreso (存款) 和 retiro (取款) 方法必须是同步的,并且包含 wait() 和 notifyAll() 逻辑来处理余额限制。
package BPA;
import java.util.Random;
public class Cuenta {
private int saldo; // 当前余额
private final int saldoMax; // 最大余额限制
private final int saldoMin; // 最小余额限制
public Cuenta(int saldoInicial, int saldoMax) {
this.saldo = saldoInicial;
this.saldoMax = saldoMax;
this.saldoMin = 1; // 最小余额固定为1
}
/**
* 取款操作
* @param nombre 执行操作的人的名称
*/
public synchronized void retiro(String nombre) {
int dinero = new Random().nextInt(350) + 1; // 随机生成取款金额 (1-350)
// 使用 while 循环检查条件,防止虚假唤醒
while ((saldo - dinero) < saldoMin) {
System.out.println(" **** 余额不足!" + nombre + " 尝试提取: " + dinero + "€,当前余额: " + getSaldo() + "€ ****");
System.out.println(" ---- " + nombre + " 正在等待存款以继续提取操作 ---- ");
try {
wait(); // 释放锁并等待,直到被通知
} catch (InterruptedException e) {
System.out.println(nombre + " 的提取操作等待被中断。");
Thread.currentThread().interrupt(); // 恢复中断状态
return; // 退出方法
}
// 唤醒后会重新检查 while 条件
}
// 条件满足,执行取款
this.saldo -= dinero;
System.out.println("Name: " + nombre + " 提取现金: " + dinero + "€, 总余额: " + getSaldo() + "€");
notifyAll(); // 通知所有等待的线程,账户状态已改变
}
/**
* 存款操作
* @param nombre 执行操作的人的名称
*/
public synchronized void ingreso(String nombre) {
int dinero = new Random().nextInt(350) + 1; // 随机生成存款金额 (1-350)
// 使用 while 循环检查条件,防止虚假唤醒
while ((saldo + dinero) > saldoMax) {
System.out.println(" **** 账户已满!" + nombre + " 尝试存入: " + dinero + "€,当前余额: " + getSaldo() + "€ ****");
System.out.println(" ---- " + nombre + " 正在等待取款以继续存款操作 ---- ");
try {
wait(); // 释放锁并等待,直到被通知
} catch (InterruptedException e) {
System.out.println(nombre + " 的存款操作等待被中断。");
Thread.currentThread().interrupt(); // 恢复中断状态
return; // 退出方法
}
// 唤醒后会重新检查 while 条件
}
// 条件满足,执行存款
this.saldo += dinero;
System.out.println("Name: " + nombre + " 存入现金: " + dinero + "€, 总余额: " + getSaldo() + "€");
notifyAll(); // 通知所有等待的线程,账户状态已改变
}
public int getSaldo() {
return saldo;
}
}关键点解析:
Persona 类代表操作账户的线程,它会不断地尝试进行存款和取款。
package BPA;
import java.util.Random;
public class Persona extends Thread {
String nombre;
private Cuenta cuenta;
public Persona(String nombre, Cuenta cuenta) {
this.nombre = nombre;
this.cuenta = cuenta;
}
@Override
public void run() {
while (true) { // 线程持续运行
// 随机决定是存款还是取款
if (new Random().nextBoolean()) {
cuenta.ingreso(nombre);
} else {
cuenta.retiro(nombre);
}
try {
// 模拟操作间隔,避免CPU空转,并让其他线程有机会执行
Thread.sleep(new Random().nextInt(1000) + 500); // 随机休眠 0.5 到 1.5 秒
} catch (InterruptedException e) {
System.out.println(nombre + " 的操作被中断。");
Thread.currentThread().interrupt(); // 恢复中断状态
break; // 退出循环
}
}
}
}关键点解析:
BPA 类是应用程序的入口点,负责创建账户和人员线程并启动它们。
package BPA;
public class BPA {
public static void main(String[] args) {
// 创建一个初始余额为40€,最大余额为500€的账户
Cuenta laCuenta = new Cuenta(40, 500);
// 创建两个操作该账户的人(线程)
Persona Ramon = new Persona("Ramon", laCuenta);
Persona Quique = new Persona("Quique", laCuenta);
// 启动线程
Quique.start();
Ramon.start();
try {
// 主线程等待两个Persona线程执行完毕(在此例中由于是无限循环,需要外部中断)
Quique.join();
Ramon.join();
} catch (InterruptedException ex) {
System.out.println("主线程被中断。");
Thread.currentThread().interrupt();
}
System.out.println("所有操作结束,最终余额: " + laCuenta.getSaldo() + "€");
}
}关键点解析:
运行上述代码,你将看到两个 Persona 线程交替进行存款和取款操作。当账户余额达到上限或下限时,相应的线程会自动进入等待状态,直到另一个线程通过操作改变了账户状态并调用 notifyAll() 将其唤醒。
重要注意事项:
以上就是Java 多线程共享账户同步机制详解的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号