Domanda

Come posso usare un ConcurrentLinkedQueue in Java?
Usando questo LinkedQueue , devo preoccuparmi della concorrenza in coda? O devo solo definire due metodi (uno per recuperare elementi dall'elenco e un altro per aggiungere elementi all'elenco)?
Nota: ovviamente questi due metodi devono essere sincronizzati. Giusto?


MODIFICA: Quello che sto cercando di fare è questo: ho una classe (in Java) con un metodo per recuperare elementi dalla coda e un'altra classe con un metodo per aggiungere elementi al coda. Gli elementi aggiunti e recuperati dall'elenco sono oggetti della mia classe.

Un'altra domanda: devo farlo nel metodo di rimozione:

while (queue.size() == 0){ 
  wait(); 
  queue.poll();
}

Ho solo un consumatore e un produttore.

È stato utile?

Soluzione

No, i metodi non devono essere sincronizzati e non è necessario definire alcun metodo; sono già in ConcurrentLinkedQueue, basta usarli. ConcurrentLinkedQueue esegue internamente tutte le operazioni di blocco e altre necessarie; il / i tuo / i produttore / i aggiunge dati nella coda e i tuoi consumatori lo sondano.

Innanzitutto, crea la tua coda:

Queue<YourObject> queue = new ConcurrentLinkedQueue<YourObject>();

Ora, ovunque tu stia creando i tuoi oggetti produttore / consumatore, passa in coda in modo che abbiano un posto dove mettere i loro oggetti (potresti usare un setter per questo, invece, ma preferisco fare questo tipo di cose in un costruttore ):

YourProducer producer = new YourProducer(queue);

e

YourConsumer consumer = new YourConsumer(queue);

e aggiungi elementi nel tuo produttore:

queue.offer(myObject);

e prendi roba nel tuo consumatore (se la coda è vuota, poll () restituirà null, quindi controlla):

YourObject myObject = queue.poll();

Per ulteriori informazioni consultare il Javadoc

EDIT:

Se devi bloccare in attesa che la coda non sia vuota, probabilmente vorrai usare un LinkedBlockingQueue e usa il metodo take (). Tuttavia, LinkedBlockingQueue ha una capacità massima (il valore predefinito è Integer.MAX_VALUE, che è oltre due miliardi) e quindi potrebbe essere o non essere appropriato a seconda delle circostanze.

Se hai solo un thread che inserisce elementi nella coda e un altro thread che estrae elementi dalla coda, ConcurrentLinkedQueue è probabilmente eccessivo. È più utile quando puoi avere centinaia o persino migliaia di thread che accedono alla coda contemporaneamente. Le tue esigenze saranno probabilmente soddisfatte utilizzando:

Queue<YourObject> queue = Collections.synchronizedList(new LinkedList<YourObject>());

Un vantaggio di questo è che si blocca sull'istanza (coda), quindi puoi sincronizzarti sulla coda per garantire l'atomicità delle operazioni composite (come spiegato da Jared). NON PUOI farlo con un ConcurrentLinkedQueue, poiché tutte le operazioni vengono eseguite SENZA il blocco sull'istanza (utilizzando le variabili java.util.concurrent.atomic). NON sarà necessario farlo se si desidera bloccare mentre la coda è vuota, poiché poll () restituirà semplicemente null mentre la coda è vuota e poll () è atomico. Verifica se poll () restituisce null. In tal caso, attendere (), quindi riprovare. Non è necessario bloccare.

Infine:

Onestamente, userei solo LinkedBlockingQueue. È ancora eccessivo per la tua applicazione, ma è probabile che funzioni bene. Se non è abbastanza performante (PROFILO!), Puoi sempre provare qualcos'altro, e significa che non devi occuparti di QUALSIASI roba sincronizzata:

BlockingQueue<YourObject> queue = new LinkedBlockingQueue<YourObject>();

queue.put(myObject); // Blocks until queue isn't full.

YourObject myObject = queue.take(); // Blocks until queue isn't empty.

Tutto il resto è uguale. Inserisci probabilmente non si bloccherà, perché non è probabile che tu inserisca due miliardi di oggetti in coda.

Altri suggerimenti

Questo è in gran parte un duplicato di un'altra domanda .

Ecco la sezione di quella risposta che è rilevante per questa domanda:

Devo eseguire la mia sincronizzazione se utilizzo java.util.ConcurrentLinkedQueue?

Le operazioni atomiche sulle raccolte simultanee sono sincronizzate per te. In altre parole, ogni singola chiamata alla coda è garantita thread-safe senza alcuna azione da parte tua. Ciò che è non garantito da thread-safe sono le operazioni eseguite sulla raccolta che non sono atomiche.

Ad esempio, questo è thread-safe senza alcuna azione da parte tua:

queue.add(obj);

o

queue.poll(obj);

Tuttavia; le chiamate non atomiche alla coda non sono automaticamente thread-safe. Ad esempio, le seguenti operazioni sono non automaticamente thread-safe:

if(!queue.isEmpty()) {
   queue.poll(obj);
}

Quest'ultimo non è sicuro per i thread, poiché è molto probabile che tra il momento in cui viene chiamato isEmpty e il tempo in cui viene chiamato il sondaggio, altri thread avranno aggiunto o rimosso elementi dalla coda. Il modo sicuro per eseguire questa operazione è il seguente:

synchronized(queue) {
    if(!queue.isEmpty()) {
       queue.poll(obj);
    }
}

Ancora una volta ... le chiamate atomiche alla coda sono automaticamente thread-safe. Le chiamate non atomiche non lo sono.

Usa il sondaggio per ottenere il primo elemento e aggiungi per aggiungere un nuovo ultimo elemento. Tutto qui, nessuna sincronizzazione o altro.

Questo è probabilmente quello che stai cercando in termini di sicurezza dei thread e amp; & Quot; prettyness " quando si tenta di consumare tutto nella coda:

for (YourObject obj = queue.poll(); obj != null; obj = queue.poll()) {
}

Questo ti garantirà di uscire quando la coda è vuota e di continuare a estrarre gli oggetti da essa finché non è vuota.

ConcurentLinkedQueue è un'implementazione molto efficiente in attesa / blocco gratuito (vedere javadoc per riferimento), quindi non solo non è necessario sincronizzare, ma la coda non bloccherà nulla, essendo praticamente veloce come una non sincronizzata (non thread-safe) uno.

Usalo come faresti con una raccolta non simultanea. Le classi simultanee [Collection] racchiudono le raccolte regolari in modo da non dover pensare alla sincronizzazione dell'accesso.

Modifica: ConcurrentLinkedList non è in realtà solo un wrapper, ma piuttosto un'implementazione simultanea migliore. Ad ogni modo, non devi preoccuparti della sincronizzazione.

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