Ejemplos

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.

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.

Copyright Jesús Aurelio Castro Magaña © 2026