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 elementosnumElements
solicitados no están disponibles, los esperará hasta el tiempo de espera especificado.