
本文深入探讨了在java多线程环境下,如何安全地管理共享资源(如银行账户)的并发访问。通过详细分析synchronized、wait()和notifyall()机制,我们展示了如何确保多线程对账户进行存取操作时的原子性和一致性,避免数据竞争和死锁,从而实现一个健壮的并发控制模型。
在现代应用程序开发中,多线程并发编程是提高系统性能和响应能力的关键技术。然而,当多个线程同时访问和修改共享资源时,如果没有适当的同步机制,就可能导致数据不一致、竞态条件甚至死锁等问题。本文将以一个经典的银行账户存取场景为例,详细讲解如何在Java中利用synchronized、wait()和notifyAll()方法实现线程间的协作与同步,确保共享账户的安全操作。
设想一个银行账户,由多个人(对应多个线程)同时进行存款(deposit)和取款(extract)操作。如果不对这些操作进行同步,可能会出现以下问题:
为了解决这些问题,我们需要引入同步机制来保证在某一时刻,只有一个线程能够访问和修改共享资源的关键部分。
Java提供了内置的同步机制,主要通过以下关键字和方法实现:
立即学习“Java免费学习笔记(深入)”;
我们将通过三个类来实现这个银行账户存取系统:
Cuenta 类是核心,它管理账户余额,并负责对存取款操作进行同步。
package BPA;
import java.util.Random;
public class Cuenta {
private int saldo; // 当前余额
private final int saldoMax; // 最大余额
private final int saldoMin = 1; // 最小余额
public Cuenta(int saldoInicial, int saldoMaximo) {
this.saldo = saldoInicial;
this.saldoMax = saldoMaximo;
}
/**
* 取款操作
* @param nombre 执行操作的人员名称
* @param cuenta 当前账户实例 (这里可以省略,因为方法内部直接使用this)
*/
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) {
Thread.currentThread().interrupt(); // 恢复中断状态
System.out.println(nombre + " 的取款操作被中断。");
return; // 退出方法
}
// 唤醒后重新生成金额,避免因唤醒后条件仍不满足而再次等待相同金额
dinero = new Random().nextInt(350) + 1;
}
// 条件满足,执行取款
this.saldo -= dinero;
System.out.println("Name: " + nombre + " 取出: " + dinero + " €,当前余额: " + getSaldo() + " €");
notifyAll(); // 通知所有等待的线程(包括存款线程和取款线程),账户状态已改变
}
/**
* 存款操作
* @param nombre 执行操作的人员名称
* @param cuenta 当前账户实例 (这里可以省略,因为方法内部直接使用this)
*/
public synchronized void ingreso(String nombre) {
int dinero = new Random().nextInt(350) + 1; // 随机生成存款金额 (1-350)
// 使用while循环检查条件,防止虚假唤醒
while ((saldo + dinero) > saldoMax) {
System.out.println(" **** 账户已达最大容量 " + saldoMax + " €。 " + nombre + " 尝试存入: " + dinero + " €,当前余额: " + getSaldo() + " € ****");
System.out.println(" ---- " + nombre + " 正在等待取款以进行存款 ---- ");
try {
wait(); // 余额超出上限,释放锁并等待
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
System.out.println(nombre + " 的存款操作被中断。");
return; // 退出方法
}
// 唤醒后重新生成金额
dinero = new Random().nextInt(350) + 1;
}
// 条件满足,执行存款
this.saldo += dinero;
System.out.println("Name: " + nombre + " 存入: " + dinero + " €,当前余额: " + getSaldo() + " €");
notifyAll(); // 通知所有等待的线程,账户状态已改变
}
public int getSaldo() {
return saldo;
}
}关键点解析:
Persona 类代表一个操作银行账户的人,它是一个线程。
package BPA;
public class Persona extends Thread {
String nombre;
private final Cuenta cuenta; // 持有对共享账户的引用
public Persona(String nombre, Cuenta cuenta) {
this.nombre = nombre;
this.cuenta = cuenta;
}
@Override
public void run() {
while (true) { // 模拟持续进行存取款操作
cuenta.ingreso(nombre); // 尝试存款
cuenta.retiro(nombre); // 尝试取款
try {
// 模拟操作间隔,让其他线程有机会执行
Thread.sleep(new Random().nextInt(1000) + 500); // 随机休眠500ms到1500ms
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println(nombre + " 线程被中断,停止运行。");
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();
// 理论上,如果线程有终止条件,这里可以使用join()等待它们结束
// 但在本例中,线程是无限循环运行的,除非被中断。
// try {
// Quique.join();
// Ramon.join();
// } catch (InterruptedException ex) {
// System.out.println("主线程被中断。");
// }
}
}运行 BPA 类,你将看到两个人员线程(Ramon 和 Quique)不断地对同一个账户进行存取款操作。当账户余额不足以取款或存款会超出上限时,相应的线程会进入等待状态,直到另一个线程通过存取款操作改变了账户状态并调用notifyAll()将其唤醒。
例如,输出可能包含:
Name: Quique 存入: 150 €,当前余额: 190 € Name: Ramon 取出: 80 €,当前余额: 110 € Name: Quique 存入: 200 €,当前余额: 310 € **** 账户已达最大容量 500 €。 Ramon 尝试存入: 250 €,当前余额: 310 € **** ---- Ramon 正在等待取款以进行存款 ---- Name: Quique 取出: 100 €,当前余额: 210 € Name: Ramon 存入: 250 €,当前余额: 460 €
这表明了线程间的协作和同步是成功的。
以上就是Java多线程并发:实现共享账户的同步存取的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号