Domanda

ho una coda di blocco degli oggetti.

Voglio scrivere un filo che blocca fino a quando non v'è un oggetto sulla coda. Simile alla funzionalità fornite da BlockingQueue.take ().

Tuttavia, dato che non so se sarò in grado di elaborare correttamente l'oggetto, voglio sbirciare solo () e non rimuovere l'oggetto. Voglio rimuovere l'oggetto solo se sono in grado di elaborare con successo.

Quindi, vorrei una funzione di blocco peek (). Attualmente, peek () restituisce solo se la coda è vuota come per le javadocs.

Mi sto perdendo qualcosa? C'è un altro modo per ottenere questa funzionalità?

Modifica

Ogni pensiero su se ho appena usato un filo di coda di sicuro e dato un'occhiata e ho dormito, invece?

public void run() {
    while (!exit) {
        while (queue.size() != 0) {
            Object o =  queue.peek();
            if (o != null) {
                if (consume(o) == true) {
                    queue.remove();
                } else {
                    Thread.sleep(10000); //need to backoff (60s) and try again
                }
            }
        }
        Thread.sleep(1000); //wait 1s for object on queue
    }
}

Si noti che ho solo un thread consumatore e uno (separato) filo produttore. Credo che questo non è efficiente come utilizzando un BlockingQueue ... Qualsiasi commento apprezzate.

È stato utile?

Soluzione

È possibile utilizzare un LinkedBlockingDeque e rimuovere fisicamente la voce dalla coda (utilizzando takeLast()), ma sostituirlo nuovamente a alla fine della coda se l'elaborazione non riesce utilizzando putLast(E e). Nel frattempo i vostri "produttori" avrebbero aggiungere elementi alla anteriore della coda utilizzando putFirst(E e).

Si può sempre incapsulare questo comportamento all'interno della propria implementazione Queue e fornire un metodo blockingPeek() che esegue takeLast() seguito da putLast() dietro le quinte sul LinkedBlockingDeque sottostante. Quindi dal punto di vista del cliente chiamando l'elemento non viene mai rimosso dalla coda.

Altri suggerimenti

  

Tuttavia, dato che non so se sarò in grado di elaborare correttamente l'oggetto, voglio sbirciare solo () e non rimuovere l'oggetto. Voglio rimuovere l'oggetto solo se sono in grado di elaborare con successo.

In generale, non è thread-safe. Che cosa succede se, dopo aver peek() e determina che l'oggetto può essere elaborato correttamente, ma prima di take() per rimuovere e di processo, un altro thread prende quell'oggetto?

L'unica cosa di cui sono a conoscenza di che cosa questo è BlockingBuffer in Apache Commons Collezioni :

  

Se sia ottenere o rimuovere è chiamato a   un buffer vuoto, il thread chiamante   attende la notifica che un componente aggiuntivo o   addAll operazione è stata completata.

get() equivale a peek(), e un Buffer può essere fatto per agire come BlockingQueue decorando un UnboundedFifoBuffer con un BlockingBuffer

Potresti anche basta aggiungere una coda di listener di eventi alla coda di blocco, poi, quando si aggiunge qualcosa al (blocco) di coda, inviare un evento ai propri ascoltatori? Si potrebbe avere il blocco filo fino a quando è il metodo actionPerformed è stato chiamato.

La risposta più immediata è, non non c'è davvero un modo avere una sbirciatina blocco, bar implementare una coda di blocco con una sbirciatina di bloccaggio () voi stessi.

  

Mi sto perdendo qualcosa?

peek () può essere fastidioso con la concorrenza -

  • Se non è possibile elaborare il peek () 'un messaggio d -. Sarà lasciata in coda, a meno che non si dispone di più i consumatori
  • che sta per ottenere l'oggetto di coda se non è possibile elaborarlo?
  • Se si dispone di più i consumatori, si ottiene una condizione di competizione tra peek () 'ing e un altro thread anche l'elaborazione di articoli, con conseguente trasformazione duplicato o peggio.

Sembra che si potrebbe essere meglio in realtà la rimozione dell'attività e elaborarlo utilizzando un Chain-of-responsabilità modello

Modifica: Re: il tuo ultimo esempio: Se avete solo 1 consumatore, non potrà mai sbarazzarsi dell'oggetto sulla coda - a meno che non è aggiornato nel frattempo - nel qual caso è meglio essere molto molto attenti filo di sicurezza e probabilmente non avrebbe dovuto mettere la voce nella coda in ogni caso.

Sembra che BlockingQueue sé non ha la funzionalità che stai specificando.

Potrei provare a re-inquadrare il problema un po 'però: quello che si potrebbe fare con gli oggetti non si può "processo in modo corretto"? Se sei solo lasciandoli nella coda, dovrete tirare fuori ad un certo punto e trattare con loro. Mi piacerebbe caldamente sia per capire come elaborarli (comunemente, se un queue.get () dà alcun tipo di valore non valido o cattivo, probabilmente siete OK per cadere solo sul pavimento) o la scelta di una struttura dati diversa da quella una FIFO.

Non è una risposta per sé, ma: JDK-6.653.412 sostiene che questo non è un caso d'uso valida.

La soluzione 'semplice'

  

non elaborano il Avanti elemento fino a quando il precedente elemento viene elaborato con successo.

public void run() {

Object lastSuccessfullyProcessedElement = null;

    while (!exit) {
        Object obj =  lastSuccessfullyProcessedElement == null ? queue.take() : lastSuccessfullyProcessedElement; // blocking

        boolean successful = process(obj);

        if(!successful) {
            lastSuccessfullyProcessedElement = obj;
        } else {
            lastSuccessfullyProcessedElement = null;
        }
    }
}
  1. Calling peek() e controllando se il valore è nullo non è CPU efficiente.

Ho visto l'utilizzo della CPU sta per il 10% sul mio sistema, quando la coda è vuota per il seguente programma.

while (true) {
   Object o = queue.peek();
   if(o == null) continue;
   // omitted for the sake of brevity
}
  1. L'aggiunta di sleep() aggiunge lentezza.

  2. L'aggiunta di nuovo alla coda utilizzando putLast disturberà l'ordine. Inoltre, è un'operazione di blocco che richiede serrature.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top