BlockingQueue: put () e isEmpty () non funzionano insieme?
-
19-08-2019 - |
Domanda
Vorrei avere un SynchronousQueue
dove inserisco elementi da un thread con put ()
, quindi l'input viene bloccato fino a quando l'elemento viene preso in un altro thread.
Nell'altro thread eseguo molti calcoli e di tanto in tanto voglio verificare se un elemento è già disponibile e consumarlo. Ma sembra che isEmpty ()
ritorni sempre vero, anche se un altro thread è in attesa alla chiamata put ()
.
Come diavolo è possibile? Ecco il codice di esempio:
@Test
public void testQueue() throws InterruptedException {
final BlockingQueue<Integer> queue = new SynchronousQueue<Integer>();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (!queue.isEmpty()) {
try {
queue.take();
System.out.println("taken!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// do useful computations here (busy wait)
}
}
});
t.start();
queue.put(1234);
// this point is never reached!
System.out.println("hello");
}
EDIT: Né isEmpty () né peek () funzionano, si deve usare poll (). Grazie!
Soluzione
Da http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/SynchronousQueue.html#put(E) :
isEmpty
pubblico booleano isEmpty ()
Restituisce sempre vero. Un SynchronousQueue non ha capacità interna.
(non l'ho esaminato in dettaglio, ma potresti dare un'occhiata a sondaggio o prendi invece)
Altri suggerimenti
Oltre alla risposta di Tim: non stai facendo nulla nel thread consumer ma chiama continuamente isEmpty () in un ciclo stretto. Invece di chiedere al sistema operativo di non eseguirlo fino a quando non c'è qualcosa di utile da fare, il thread del consumatore è costantemente occupato. Anche se isEmpty ha funzionato correttamente, il thread del produttore raramente avrebbe la possibilità di essere eseguito.
Potresti (se isEmpty () ha funzionato, o sei passato all'utilizzo di poll ()) far dormire il consumatore per un po 'tra i test quando la coda è vuota per dare al produttore la possibilità di eseguire, o (preferibilmente) solo elimina il test isEmpty () e lascia che il thread si blocchi sul mutex all'interno di take () in modo sensato anziché effettuare il polling.
sembra che il tuo codice stia provando a fare un sondaggio. perché non chiamare semplicemente il metodo poll ()?