2011-09-26 22 views
8

Estoy leyendo el libro Java Concurrency in Practice. En una sección sobre java.util.concurrent.Semaphore, las siguientes líneas están presentes en el libro. Es un comentario sobre su aplicación del "permiso virtual" objetos¿Cómo y por qué un Semáforo puede otorgar más permisos de los que se inicializaron?

La aplicación no tiene objetos de permisos reales, y Semaphore no no asocia los permisos prescindido de hilos, por lo que un permiso adquirió en un hilo puede ser liberado de otro hilo. Puede pensar en acquire como consumir un permiso y release como crear uno; a Semaphore no se limita al número de permisos con los que se creó.

¿Alguien puede explicar esto? Estoy teniendo problemas para entender esto. Si creamos un grupo de tamaño fijo, creamos un número fijo de "permisos". De la declaración anterior, parece que los "permisos" pueden seguir creciendo. ¿Por qué está diseñado de esta manera?

+0

parece que solo frase ornamentada – gstackoverflow

Respuesta

8

En lugar de "entregar" objetos con permiso, la implementación solo tiene un contador. Cuando se "crea" un nuevo permiso, el contador aumenta, cuando se "devuelve" un permiso, el contador disminuye.

Esto proporciona un rendimiento mucho mejor que crear objetos reales todo el tiempo.

La desventaja es que el semáforo en sí no puede detectar ciertos tipos de errores de programación (como el ingreso de permisos no autorizados o fugas de semáforos). Como codificador, debes asegurarte de seguir las reglas por tu cuenta.

+0

¿Proporciona Java un tipo diferente de semáforo que realmente impone el límite del permiso? Solo quiero que Release() sea un no-operativo cuando todos los permisos ya han sido lanzados ... En un sistema complejo con muchos hilos, no es tan fácil asegurarse de que cada hilo siempre adquiera y libere exactamente un permiso . – Dasmowenator

+0

@Dasmowenator: supongo que puede hacer su propio sobre AtomicInteger. Pero eso no suena como un buen enfoque. Deberías asegurarte de que tu código de bloqueo sea lógicamente correcto. Si encuentra la necesidad de hacer que la liberación sea no operativa, eso probablemente signifique que alguien estaba liberando más bloqueos de los que debería tener. Y eso romperá cosas que no se pueden arreglar simplemente ignorando algunas llamadas de semáforo. – Thilo

+0

También podría usar la forma tradicional de bloqueo "sincronizado". Menos flexible, pero seguro (sin fugas, se encarga de la reincorporación, etc.). – Thilo

5

¿Alguien puede explicar esto? De la declaración anterior, parece que los "permisos" pueden seguir creciendo.

Un semáforo es un contador de permisos. adquirir es como una disminución que espera en lugar de ir por debajo de cero. No tiene un límite superior.

¿Por qué está diseñado de esta manera?

Porque es simple hacerlo.

+0

Sin límite superior, ¿no sería el límite superior el número de permisos? – Scorpion

+0

El límite superior es el número de veces que se libera menos el número de veces que se ha llamado a adquirir. Puede llamar a la liberación cualquier cantidad de veces. Hay un límite superior de Integer.MAX_VALUE en algunas implementaciones. –

+0

Entonces, ¿cómo se hace para crear un semáforo sólido con un máximo de 1, independientemente de cuántas veces se llame? – slott

2

Creo que significa los tiempos que podemos necesitar Semáforo como las veces que lanzamos "extra" y más los permisos que creó.

Tales como:

Semaphore s = new Semaphore(1); // one permit when initialize 

s.acquire(); 
s.release(); 

s.release(); // "extra" release. 

En este momento, este semáforo permite un permiso originalmente y un permiso "extra"

-1

Tal vez la última línea "un semáforo no se limita a la cantidad de permisos que fue creado con "es tu fuente de confusión.

Un semáforo cuando se crea se inicializa con un conjunto fijo de permisos. Esto se convierte en el número máximo de permisos que el semáforo puede dispensar simultáneamente en cualquier momento durante el tiempo de vida de ese semáforo. Usted no puede aumentar dinámicamente este número excepto reinicializando el semáforo.

El significado si la línea citada (de JCIP) es esta: Primero, la semántica de cómo funciona un semáforo no se limita a los detalles de emisión y recuperación de un permiso, esto se manifiesta en el hecho de que cualquier hilo puede tiene acceso al semáforo puede tener un permiso liberado (aunque este hilo no poseía el permiso en primer lugar)

En segundo lugar, puede reducir dinámicamente los permisos máximos de un semáforo - llamando al método reducePermits(int).

3

Como se mencionó en primer mensaje "semáforo no está limitado a la cantidad de permisos que fue creada con"

Cada llamada a .release() de la API aumentará el número de permiso por uno. Así que Semáforos no tiene un tamaño de permiso fijo

+0

¿Puedes explicar el funcionamiento de .release() entonces? Entonces, si creo un objeto de semáforo con 0, ¿entonces ningún hilo puede obtener permiso de él? Pero si llamo .release() primero y luego .acquire() en la línea siguiente, ¿permitirá que un hilo adquiera un permiso? –

1

Es sorprendente para algunos de nosotros.

Puede subclasificar fácilmente un semáforo delimitado.

/** 
* Terrible performance bounded semaphore. 
**/ 
public class BoundedSemaphore extends Semaphore { 
    private static final long serialVersionUID = -570124236163243243L; 
    final int bound; 
    public BoundedSemaphore(int permits) { 
     super(permits); 
     bound=permits; 
    } 

    @Override 
    synchronized public void acquire() throws InterruptedException { 
     super.acquire(); 
    } 

    @Override 
    synchronized public boolean tryAcquire() { 
     return super.tryAcquire(); 
    } 

    @Override 
    synchronized public void release() { 
     if(availablePermits()<bound){ 
      super.release(); 
     } 
    } 
    @Override 
    synchronized public void acquire(int count) throws InterruptedException { 
     super.acquire(count); 
    } 

    @Override 
    synchronized public boolean tryAcquire(int count) { 
     return super.tryAcquire(count); 
    } 

    @Override 
    synchronized public void release(int count) { 
     if(availablePermits()<bound){ 
      super.release(bound-availablePermits()); 
     } 
    } 
} 
Cuestiones relacionadas