Un semáforo en Java es una ayuda de sincronización que restringe la cantidad de subprocesos que pueden acceder a un recurso compartido en un momento dado. Es parte del paquete java.util.concurrent y se utiliza para administrar el acceso simultáneo a recursos, como archivos, bases de datos o conexiones de red.
Un semáforo controla el acceso a un número determinado de permisos. Cada permiso representa el derecho a acceder a un recurso en particular. El semáforo realiza un seguimiento de la cantidad de permisos disponibles, lo que determina cuántos subprocesos pueden acceder al recurso simultáneamente.
Permiso: un token o ticket que permite que un hilo continúe accediendo a un recurso compartido.
Cuando creas un semáforo, especificas el número de permisos disponibles. Este número define cuántos subprocesos pueden acceder al recurso simultáneamente.
Antes de que un hilo pueda acceder al recurso, debe adquirir un permiso del semáforo. Esto se hace usando el método adquirir().
Adquirir: este método se llama cuando un hilo quiere acceder al recurso. Si hay un permiso disponible, el semáforo disminuye el número de permisos disponibles y permite que el hilo continúe. Si no hay permisos disponibles, el hilo se bloquea hasta que haya un permiso disponible.
Comportamiento de bloqueo: si no hay permisos disponibles, el subproceso que llama a adquirir() se bloqueará (es decir, esperará) hasta que otro subproceso libere un permiso.
Una vez que un hilo ha terminado de usar el recurso, debe liberar el permiso para que esté disponible para otros hilos. Esto se hace usando el método release().
Release: este método incrementa la cantidad de permisos disponibles. Si hay hilos esperando un permiso, uno de ellos será desbloqueado y se le permitirá adquirir el permiso.
Hay dos tipos de semáforos en Java:
Para comprender mejor cómo funcionan los semáforos, veamos una implementación práctica. Crearemos un escenario simple en el que varios subprocesos intentan acceder a un recurso limitado.
import java.util.concurrent.Semaphore; public class SemaphoreDemo { // Creating a semaphore with 3 permits private static final Semaphore semaphore = new Semaphore(3); public static void main(String[] args) { // Creating and starting 6 threads for (int i = 1; i2.2 Explicación del Código
En este ejemplo, creamos un semáforo con tres permisos, lo que significa que solo tres subprocesos pueden acceder a la sección crítica del código en un momento dado. Luego creamos seis subprocesos, todos los cuales intentan adquirir un permiso. Una vez que un hilo adquiere un permiso, simula algún trabajo durmiendo durante dos segundos antes de liberar el permiso.
2.3 Observando la salida
Cuando ejecute el código anterior, el resultado se verá así:
Worker 1 is trying to acquire a permit... Worker 1 acquired a permit. Worker 2 is trying to acquire a permit... Worker 2 acquired a permit. Worker 3 is trying to acquire a permit... Worker 3 acquired a permit. Worker 4 is trying to acquire a permit... Worker 5 is trying to acquire a permit... Worker 6 is trying to acquire a permit... Worker 1 is releasing a permit. Worker 4 acquired a permit. Worker 2 is releasing a permit. Worker 5 acquired a permit. Worker 3 is releasing a permit. Worker 6 acquired a permit.Aquí, los primeros tres hilos adquieren exitosamente los permisos y comienzan sus tareas. Los subprocesos restantes deben esperar hasta que se emita un permiso antes de poder continuar.
2.4 Casos de uso prácticos
Los semáforos son particularmente útiles en escenarios donde es necesario limitar la cantidad de accesos simultáneos a un recurso en particular, como por ejemplo:
Si bien los semáforos son una herramienta poderosa, tienen su propio conjunto de ventajas y desventajas.
Flexibilidad: los semáforos permiten un control preciso sobre el acceso a los recursos por parte de múltiples subprocesos.
Escalabilidad: los semáforos pueden gestionar fácilmente el acceso a una gran cantidad de recursos.
Equidad: los semáforos se pueden configurar para garantizar que los subprocesos adquieran permisos de manera justa.
Complejidad: el uso de semáforos puede introducir complejidad en el código, lo que dificulta la depuración.
Interbloqueos: si no se manejan correctamente, los semáforos pueden provocar interbloqueos en los que los subprocesos quedan bloqueados indefinidamente en espera de permisos.
Para evitar errores comunes y aprovechar al máximo los semáforos, considere las siguientes mejores prácticas:
En lugar de usar adquirir(), que bloquea indefinidamente, puedes usar tryAcquire() para intentar adquirir un permiso con un tiempo de espera. Esto evita que los hilos se queden atascados en espera.
if(semaphore.tryAcquire(1000, TimeUnit.MILLISECONDS)) { try { // Critical section } finally { semaphore.release(); } }
Para evitar fugas de recursos, libere siempre el permiso en un bloque finalmente. Esto garantiza que el permiso se libere incluso si ocurre una excepción.
Si solo necesita bloquear y desbloquear un recurso para un solo subproceso, considere usar ReentrantLock o sincronizado en lugar de un semáforo binario.
Los semáforos son una herramienta poderosa para administrar la concurrencia en Java, lo que le permite controlar la cantidad de subprocesos que acceden a un recurso compartido. Si sigue las técnicas y mejores prácticas descritas en este artículo, podrá implementar semáforos de forma eficaz en sus aplicaciones Java para garantizar una gestión de recursos segura y eficiente.
Si tienes alguna pregunta o te gustaría compartir tus propias experiencias con los semáforos, ¡no dudes en comentar a continuación!
Lea más publicaciones en: Técnicas para gestionar la concurrencia en Java utilizando semáforos
Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.
Copyright© 2022 湘ICP备2022001581号-3