Planteamiento
Un banco tiene un sistema para que varios clientes puedan realizar operaciones simultáneamente en distintos cajeros automáticos. Cada cliente puede realizar depósitos o retiros de su cuenta. El sistema debe garantizar que las operaciones sean seguras y que no haya inconsistencias en los saldos de las cuentas, incluso cuando varios clientes acceden a la misma cuenta al mismo tiempo.
Requisitos
- Clases necesarias:
- Una clase
CuentaBancaria
que represente una cuenta con métodos para depositar y retirar dinero. - Una clase
Cliente
que represente a los hilos que realizan operaciones en las cuentas.
- Una clase
- Gestión de operaciones:
- El sistema debe garantizar que las operaciones sean seguras utilizando sincronización para evitar condiciones de carrera.
- Si un cliente intenta retirar más dinero del que hay en la cuenta, debe mostrarse un mensaje de error.
- Simulación:
- Simula un sistema con 3 cuentas bancarias y 5 clientes.
- Cada cliente debe realizar 3 operaciones aleatorias (depósitos o retiros) en una cuenta seleccionada también de forma aleatoria.
- Salida esperada:
- Muestra mensajes indicando qué cliente realiza qué operación, en qué cuenta, y el saldo resultante.
Estructura del Código
import java.util.Random;
class CuentaBancaria {
private int saldo;
public CuentaBancaria(int saldoInicial) {
this.saldo = saldoInicial;
}
public synchronized void depositar(int cantidad) {
saldo += cantidad;
System.out.println(Thread.currentThread().getName() + " depositó: " + cantidad + " - Saldo actual: " + saldo);
}
public synchronized void retirar(int cantidad) {
if (cantidad <= saldo) {
saldo -= cantidad;
System.out.println(Thread.currentThread().getName() + " retiró: " + cantidad + " - Saldo actual: " + saldo);
} else {
System.out.println(Thread.currentThread().getName() + " intentó retirar: " + cantidad + " - Saldo insuficiente");
}
}
}
class Cliente implements Runnable {
private final CuentaBancaria[] cuentas;
private final Random random = new Random();
public Cliente(CuentaBancaria[] cuentas) {
this.cuentas = cuentas;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
int cuentaIndex = random.nextInt(cuentas.length);
CuentaBancaria cuenta = cuentas[cuentaIndex];
int operacion = random.nextInt(2); // 0 para depósito, 1 para retiro
int cantidad = random.nextInt(500) + 1; // Operaciones entre 1 y 500
if (operacion == 0) {
cuenta.depositar(cantidad);
} else {
cuenta.retirar(cantidad);
}
try {
Thread.sleep(1000); // Simula tiempo entre operaciones
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
public class Banco {
public static void main(String[] args) {
// Crear 3 cuentas bancarias con saldos iniciales
CuentaBancaria[] cuentas = {
new CuentaBancaria(1000),
new CuentaBancaria(2000),
new CuentaBancaria(3000)
};
// Crear 5 clientes
for (int i = 1; i <= 5; i++) {
Thread cliente = new Thread(new Cliente(cuentas), "Cliente-" + i);
cliente.start();
}
}
}
Requisitos de Salida
El programa debe mostrar mensajes como los siguientes:
Cliente-1 depositó: 200 - Saldo actual: 1200
Cliente-2 retiró: 300 - Saldo actual: 1700
Cliente-3 intentó retirar: 4000 - Saldo insuficiente
Cliente-4 depositó: 500 - Saldo actual: 3500
Cliente-5 retiró: 1000 - Saldo actual: 2000
Puntos de Evaluación
- Uso correcto de sincronización (
synchronized
) para garantizar la seguridad de las operaciones. - Simulación realista de concurrencia con múltiples hilos que representan a los clientes.
- Validación adecuada para evitar retiros cuando el saldo es insuficiente.
- Salida clara y consistente que permita seguir las operaciones realizadas.
Este ejercicio combina los conceptos de concurrencia, sincronización y manejo de recursos compartidos de manera práctica y relevante.