Ejemplo 7: Condiciones de carrera en Java
En este artículo recrearemos una condición de carrera en Java utilizando un ejemplo práctico para ilustrar el concepto y las consecuencias de las condiciones de carrera en la programación concurrente.
Descripción del problema
Supongamos que tienes una clase Product que representa un producto en una tienda en línea. Esta clase tiene un método decreaseStock() que reduce el stock del producto en una cantidad específica. Si varios clientes intentan comprar el mismo producto al mismo tiempo, podrían ocurrir condiciones de carrera que resulten en un stock negativo o en la venta de más productos de los disponibles.
Ejemplo de código
Clase Product
public class Product {
private String name;
private int stock;
public Product(String name, int stock) {
this.name = name;
this.stock = stock;
}
public void decreaseStock(int quantity) {
if (stock >= quantity) {
stock -= quantity;
IO.println("Stock decreased by " + quantity + ". Remaining stock: " + stock);
} else {
IO.println("Not enough stock to decrease by " + quantity + ". Remaining stock: " + stock);
}
}
public int getStock() {
return stock;
}
public String getName() {
return name;
}
}
Simulación de condiciones de carrera
public class RaceConditionExample {
void main() throws InterruptedException {
Product product = new Product("Laptop", 10);
Runnable purchaseTask = () -> {
for (int i = 0; i < 5; i++) {
product.decreaseStock(1);
}
};
Thread thread1 = new Thread(purchaseTask);
Thread thread2 = new Thread(purchaseTask);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
IO.println("Final stock: " + product.getStock());
}
}
En este ejemplo, hemos creado una clase Product con un método decreaseStock() que reduce el stock del producto. Luego, en la clase RaceConditionExample, hemos simulado dos hilos que intentan comprar el mismo producto al mismo tiempo, lo que puede resultar en una condición de carrera. Debido a la falta de sincronización en el método decreaseStock(), es posible que el resultado final no sea el esperado, y el stock podría llegar a ser negativo o mostrar un número incorrecto de productos restantes.
Clase Product con sincronización
public class Product {
private String name;
private int stock;
public Product(String name, int stock) {
this.name = name;
this.stock = stock;
}
public synchronized void decreaseStock(int quantity) {
if (stock >= quantity) {
stock -= quantity;
IO.println("Stock decreased by " + quantity + ". Remaining stock: " + stock);
} else {
IO.println("Not enough stock to decrease by " + quantity + ". Remaining stock: " + stock);
}
}
public int getStock() {
return stock;
}
public String getName() {
return name;
}
}
En esta versión de la clase Product, hemos sincronizado el método decreaseStock() para asegurarnos de que solo un hilo pueda acceder a él a la vez. Esto evita las condiciones de carrera y garantiza que el stock se actualice correctamente, incluso cuando varios hilos intentan comprar el mismo producto simultáneamente.
Conclusión
En este artículo, hemos recreado una condición de carrera en Java utilizando un ejemplo práctico con una clase Product y un método decreaseStock(). Hemos demostrado cómo la falta de sincronización puede llevar a resultados impredecibles y cómo la sincronización adecuada puede resolver este problema, garantizando que el stock se actualice correctamente incluso en situaciones concurrentes. Es crucial entender las condiciones de carrera y aplicar las mejores prácticas de sincronización para evitar problemas en la programación concurrente.
Ejemplo 06: Manejando Hilos de formas Diferentes en Java
En este ejemplo, exploraremos diferentes formas de manejar hilos en Java, incluyendo la creación de hilos utilizando la clase `Thread`, la interfaz `Runnable`, y el uso de las funciones `sleep`, `join` e interrupciones para controlar la ejecución de los hilos.
Ejemplo 8: Control de acceso a recursos compartidos con semáforos
En este artículo se presentará un ejemplo práctico de cómo utilizar semáforos en Java para controlar el acceso a recursos compartidos en un entorno concurrente, evitando condiciones de carrera y garantizando la sincronización entre hilos.