Ejemplo 8: Control de acceso a recursos compartidos con semáforos
En este ejemplo, se presentará un caso práctico de cómo utilizar semáforos en Java para controlar el acceso a recursos compartidos en un entorno concurrente.
Descripción del problema
Supongamos que tenemos un recurso compartido, como una impresora, que solo puede ser utilizada por un hilo a la vez. Si varios hilos intentan acceder a la impresora simultáneamente, podríamos tener una condición de carrera que podría llevar a resultados impredecibles. Para evitar esto, podemos utilizar un semáforo para controlar el acceso a la impresora.
Solución con semáforos
En este ejemplo, se utilizará un semáforo para controlar el acceso a la impresora. El semáforo se inicializará con un permiso, lo que significa que solo un hilo podrá acceder a la impresora al mismo tiempo.
Por consiguiente, lo primero es crear la clase Printer que representará la impresora compartida:
public class Printer {
private Semaphore semaphore;
public Printer(Semaphore semaphore) {
this.semaphore = semaphore;
}
public void print(String document) {
try {
// Adquirir un permiso del semáforo
semaphore.acquire();
System.out.println("Printing: " + document);
Thread.sleep(2000); // Simular tiempo de impresión
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// Liberar el permiso del semáforo
semaphore.release();
}
}
}
En esta clase, el método print() adquiere un permiso del semáforo antes de imprimir el documento y lo libera después de completar la impresión.
A continuación, se creará la clase Worker que representará a los hilos que intentarán acceder a la impresora:
public class Worker implements Runnable {
private Printer printer;
private String document;
public Worker(Printer printer, String document) {
this.printer = printer;
this.document = document;
}
@Override
public void run() {
printer.print(document);
}
}
En esta clase, el método run() llama al método print() de la impresora para imprimir el documento.
Finalmente, se creará la clase Main para iniciar los hilos y probar el control de acceso a la impresora:
import java.util.concurrent.Semaphore;
import java.lang.Thread;
void main(){
Semaphore semaphore = new Semaphore(1); // Permitir solo un hilo a la vez
Printer printer = new Printer(semaphore);
Thread worker1 = new Thread(new Worker(printer, "Document 1"));
Thread worker2 = new Thread(new Worker(printer, "Document 2"));
Thread worker3 = new Thread(new Worker(printer, "Document 3"));
worker1.start();
worker2.start();
worker3.start();
}
En este ejemplo, se crea un semáforo con un permiso, lo que significa que solo un hilo podrá acceder a la impresora al mismo tiempo. Al iniciar los hilos worker1, worker2 y worker3, cada uno intentará imprimir su documento, pero solo uno de ellos podrá acceder a la impresora a la vez, garantizando así la sincronización entre los hilos y evitando condiciones de carrera.
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.
Ejemplo 9: El restaurante y los pedidos
En este ejemplo se muestra cómo un restaurante maneja los pedidos de los clientes utilizando un sistema de colas. Se explicará cómo se procesan los pedidos, cómo se asignan a los cocineros y cómo se asegura que los clientes reciban sus pedidos de manera eficiente.