threads thread practice example java concurrency

practice - thread java



BlockingQueue-bloqueado métodos draTo() (5)

¿Te refieres al comentario en el JavaDoc :

Además, el comportamiento de esta operación no está definido si la colección especificada se modifica mientras la operación está en curso.

Creo que esto se refiere a la list la colección en su ejemplo:

blockingQueue.drainTo(list);

lo que significa que no puede modificar la list al mismo tiempo que está vaciando del blockingQueue de la blockingQueue en la list . Sin embargo, la cola de bloqueo se sincroniza internamente, de modo que cuando se llama a drainTo , las drainTo y (ver nota abajo) se bloquean. Si no lo hiciera, entonces no sería realmente seguro para subprocesos. Puede mirar el código fuente y verificar que drainTo es seguro para subprocesos con respecto a la cola de bloqueo.

Alternativamente, ¿quiere decir que cuando llama a drainTo que desea que se bloquee hasta que al menos un objeto se haya agregado a la cola? En ese caso, tienes pocas opciones aparte de:

list.add(blockingQueue.take()); blockingQueue.drainTo(list);

para bloquear hasta que se hayan agregado uno o más elementos y luego vaciar toda la cola en la list recopilación.

Nota: A partir de Java 7, se usa un bloqueo separado para obtener y poner. Ahora se permiten las operaciones de colocación durante un drenaje (y varias otras operaciones de toma).

BlockingQueue tiene el método denominado drainTo () pero no está bloqueado. Necesito una cola que quiera bloquear pero que también pueda recuperar objetos en cola en un solo método.

Object first = blockingQueue.take(); if ( blockingQueue.size() > 0 ) blockingQueue.drainTo( list );

Supongo que el código anterior funcionará, pero estoy buscando una solución elegante.


Código fuente:

596: public int drainTo(Collection<? super E> c) { //arg. check 603: lock.lock(); 604: try { 608: for (n = 0 ; n != count ; n++) { 609: c.add(items[n]); 613: } 614: if (n > 0) { 618: notFull.signalAll(); 619: } 620: return n; 621: } finally { 622: lock.unlock(); 623: } 624: }

ArrayBlockingQueue está ansioso por devolver 0. Por cierto, podría hacerlo antes de tomar el bloqueo.


Con la API disponible, no creo que vaya a ser mucho más elegante. Aparte de que puede quitar la prueba de tamaño.

Si desea recuperar atómicamente una secuencia contigua de elementos, incluso si otra operación de eliminación coincide, no creo que ni el drainTo garantice.


Encontré este patrón útil.

List<byte[]> blobs = new ArrayList<byte[]>(); if (queue.drainTo(blobs, batch) == 0) { blobs.add(queue.take()); }


Si usas Google Guava, hay un ingenioso método Queues.drain() .

Drena la cola como BlockingQueue.drainTo(Collection, int) , pero si los elementos numElements solicitados no están disponibles, los esperará hasta el tiempo de espera especificado.