2009-05-21 8 views
5

Esta pregunta se relaciona con una de mis preguntas anteriores ..El bloqueo de cola - Necesidad de más información

Previous Post

Allí la naturaleza de bloqueo se menciona como una ventaja.

Intenté desarrollar un código simple para demostrar la naturaleza de bloqueo, pero me quedé atascado. Intenté hacer un BlockingQueue de tamaño 4 e intenté agregar 5 elementos y terminé con un java.lang.IllegalStateException. ¿Alguien puede mostrarme un ejemplo de código para bloquear la naturaleza de BlockingQueue?


public static void main(String[] args) { 
    BlockingQueue<String> bq = new LinkedBlockingQueue<String>(4); 

    try { 
     bq.offer("A"); 
     bq.offer("B"); 
     bq.offer("C"); 
     bq.offer("D"); 
     bq.offer("E"); 

     System.out.println("1 = " + bq.take()); 
     System.out.println("2 = " + bq.take()); 
     System.out.println("3 = " + bq.take()); 
     System.out.println("4 = " + bq.take()); 
     System.out.println("5 = " + bq.take()); 
     System.out.println("6 = " + bq.take()); 
    } catch (Exception e) { 
     // TODO: handle exception 
     e.printStackTrace(); 
    } 
} 

He utilizado este segmento de código. En este caso, intento poner 5 elementos en una cola con tamaño 4. En este caso, se deben agregar 4 elementos (A, B, C, D) a la cola. Luego estoy llamando al método take() mientras imprimo. ¿No debería insertarse "E" automáticamente en la cola cuando llamo al System.out.println("1 = " + bq.take());? Porque se pone una ranura gratis?

Respuesta

11

¿Se le añadió con add, offer o put? Supongo que estaba usando add, ya que es el único que puede arrojar un IllegalStateException; pero si lee el table, verá que si desea semántica de bloqueo, debe usar put (y take para eliminar).

Editar: Hay un par de problemas con su ejemplo.

Primero responderé a la pregunta "¿Por qué E no se inserta cuando llamo a take() la primera vez?" La respuesta es que cuando usted llama al take(), ya ha intentado y ha fallado para insertar E. Entonces no hay nada que insertar una vez que se ha liberado el espacio.

Ahora si ha cambiado offer() a , put("E") nunca volverá. ¿Por qué?Porque está esperando algún otro hilo para eliminar un elemento de la cola. Recuerde, BlockingQueues están diseñados para múltiples hilos de acceso. El bloqueo es inútil (en realidad peor que inútil) si tiene una aplicación de un solo subproceso.

Aquí se muestra un ejemplo mejorado:

public static void main(String[] args) { 
    final BlockingQueue<String> bq = new LinkedBlockingQueue<String>(4); 

    Runnable producer = new Runnable() { 
     public void run() { 
      try { 
       bq.put("A"); 
       bq.put("B"); 
       bq.put("C"); 
       bq.put("D"); 
       bq.put("E"); 
      } catch (InterruptedException ex) { 
       Thread.currentThread().interrupt(); 
      } 
     } 
    }; 
    Runnable consumer = new Runnable() { 
     public void run() { 
      try { 
       System.out.println("1 = " + bq.take()); 
       System.out.println("2 = " + bq.take()); 
       System.out.println("3 = " + bq.take()); 
       System.out.println("4 = " + bq.take()); 
       System.out.println("5 = " + bq.take()); 
       System.out.println("6 = " + bq.take()); 
      } catch (InterruptedException ex) { 
       Thread.currentThread().interrupt(); 
      } 
     } 
    }; 
    new Thread(producer).start(); 
    new Thread(consumer).start(); 
} 

Ahora la llamada put("E") realmente tener éxito, ya que ahora puede esperar hasta que el hilo consumidor retira "A" de la cola. El último take() seguirá bloqueándose infinitamente, ya que no hay un sexto elemento para eliminar.

+0

Anteriormente utilicé Add + Poll. Pero en este momento estoy probando put + Take –

+0

Hmm .... Entender ... Experimentar ahora :) –

+0

¿Cómo debo especificar el tiempo de espera para el PUT()? –

2

mmyers me latió: P (+1)
que debería ser lo que necesita, ¡buena suerte!

NOTA: put() fallará en su ejemplo porque put() bloqueará hasta que haya espacio disponible. Como el espacio nunca está disponible, el programa nunca continúa la ejecución.

==== vieja respuesta ======

un BlockingQueue es una interfaz, que tendrá que utilizar una de las clases implementating.

La "naturaleza de bloqueo" simplemente indica que puede solicitar algo de su cola, y si está vacía, el hilo que está bloque (espera) hasta que algo se agregue a la cola y luego continúe procesando.

ArrayBlockingQueue
DelayQueue
LinkedBlockingQueue
PriorityBlockingQueue
SynchronousQueue

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html

//your main collection 
LinkedBlockingQueue<Integer> lbq = new LinkedBlockingQueue<Integer>(); 

//Add your values 
lbq.put(100); 
lbq.put(200); 

//take() will actually remove the first value from the collection, 
//or block if no value exists yet. 
//you will either have to interrupt the blocking, 
//or insert something into the queue for the program execution to continue 

int currVal = 0; 
try { 
    currVal = lbq.take(); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} 

+0

Gracias .. he usado "LinkedBlockingQueue" –

+0

impresionante, es que todo lo que necesita? Estoy trabajando en un ejemplo en este momento si todavía quieres que lo publique –

+0

Es mejor que lo publiques. Solo un pequeño ejemplo :) –

1

Para responder específicamente a su pregunta: La oferta es una llamada de oferta sin bloqueo, por lo que en un único método como el que publicó, la llamada a oferta ('E') simplemente devuelve falso sin modificar la cola completa. Si usó la llamada de bloqueo ('E'), durmió hasta que haya espacio disponible. Para siempre en tu simple ejemplo. Debería tener una lectura de hilo separada de la cola para crear espacio para que termine la puesta.

+0

reemplaza la oferta por put pero falla. ¿Debo usar un hilo separado para PUT() los elementos? –

+0

En mi respuesta, dije: Necesitaría tener una lectura de hilo separada de la cola para crear espacio para que el put se complete. – lostlogic

+0

Sí. Entendido :) –

0

Hola más información de esta clase

/** 
* Inserts the specified element into this queue if it is possible to do 
* so immediately without violating capacity restrictions, returning 
* {@code true} upon success and throwing an 
* {@code IllegalStateException} if no space is currently available. 
* When using a capacity-restricted queue, it is generally preferable to 
* use {@link #offer(Object) offer}. 
* 
* @param e the element to add 
* @return {@code true} (as specified by {@link Collection#add}) 
* @throws IllegalStateException if the element cannot be added at this 
*   time due to capacity restrictions 
* @throws ClassCastException if the class of the specified element 
*   prevents it from being added to this queue 
* @throws NullPointerException if the specified element is null 
* @throws IllegalArgumentException if some property of the specified 
*   element prevents it from being added to this queue 
*/ 
boolean add(E e); 

/** 
* Inserts the specified element into this queue if it is possible to do 
* so immediately without violating capacity restrictions, returning 
* {@code true} upon success and {@code false} if no space is currently 
* available. When using a capacity-restricted queue, this method is 
* generally preferable to {@link #add}, which can fail to insert an 
* element only by throwing an exception. 
* 
* @param e the element to add 
* @return {@code true} if the element was added to this queue, else 
*   {@code false} 
* @throws ClassCastException if the class of the specified element 
*   prevents it from being added to this queue 
* @throws NullPointerException if the specified element is null 
* @throws IllegalArgumentException if some property of the specified 
*   element prevents it from being added to this queue 
*/ 
boolean offer(E e); 

/** 
* Inserts the specified element into this queue, waiting if necessary 
* for space to become available. 
* 
* @param e the element to add 
* @throws InterruptedException if interrupted while waiting 
* @throws ClassCastException if the class of the specified element 
*   prevents it from being added to this queue 
* @throws NullPointerException if the specified element is null 
* @throws IllegalArgumentException if some property of the specified 
*   element prevents it from being added to this queue 
*/ 
void put(E e) throws InterruptedException; 

/** 
* Inserts the specified element into this queue, waiting up to the 
* specified wait time if necessary for space to become available. 
* 
* @param e the element to add 
* @param timeout how long to wait before giving up, in units of 
*  {@code unit} 
* @param unit a {@code TimeUnit} determining how to interpret the 
*  {@code timeout} parameter 
* @return {@code true} if successful, or {@code false} if 
*   the specified waiting time elapses before space is available 
* @throws InterruptedException if interrupted while waiting 
* @throws ClassCastException if the class of the specified element 
*   prevents it from being added to this queue 
* @throws NullPointerException if the specified element is null 
* @throws IllegalArgumentException if some property of the specified 
*   element prevents it from being added to this queue 
*/ 
boolean offer(E e, long timeout, TimeUnit unit) 
    throws InterruptedException; 

/** 
* Retrieves and removes the head of this queue, waiting if necessary 
* until an element becomes available. 
* 
* @return the head of this queue 
* @throws InterruptedException if interrupted while waiting 
*/ 
E take() throws InterruptedException; 

/** 
* Retrieves and removes the head of this queue, waiting up to the 
* specified wait time if necessary for an element to become available. 
* 
* @param timeout how long to wait before giving up, in units of 
*  {@code unit} 
* @param unit a {@code TimeUnit} determining how to interpret the 
*  {@code timeout} parameter 
* @return the head of this queue, or {@code null} if the 
*   specified waiting time elapses before an element is available 
* @throws InterruptedException if interrupted while waiting 
*/ 
E poll(long timeout, TimeUnit unit) 
    throws InterruptedException; 
Cuestiones relacionadas