JavaRush /Java Blog /Random-IT /Esempio SynchronousQueue in Java: risoluzione del problem...
profeg
Livello 18

Esempio SynchronousQueue in Java: risoluzione del problema Producer Consumer

Pubblicato nel gruppo Random-IT
Esempio SynchronousQueue in Java: risoluzione del problema Producer Consumer
SynchronousQueue è un tipo speciale di BlockingQueue in cui ogni operazione di inserimento deve attendere un comando di rimozione corrispondente in un altro thread e viceversa. Quando chiami il metodo put() su una SynchronousQueue, si blocca finché un altro thread non prende quell'elemento da esso. Di conseguenza, se un altro thread tenta di rimuovere un elemento da esso e l'elemento non è presente, quel thread si blocca finché l'altro thread non inserisce l'elemento in coda. Puoi pensare a SynchronousQueue come un atleta ( filo ) che corre con la torcia olimpica, corre con la torcia (l'oggetto che viene passato) e la passa a un altro atleta che aspetta dall'altra parte. Se presti attenzione al nome, capirai che SynchronousQueue si chiama così per un motivo: trasferisce i dati in modo sincrono a un altro thread ; aspetta che qualcuno prenda i dati invece di inserirli e uscire (un'operazione asincrona). Se hai familiarità con CSP e Ada, allora saprai che le code sincronizzate sono simili all'incontro dei thread. Sono particolarmente adatti per costrutti di trasferimento di controllo in cui un oggetto in esecuzione in un thread deve sincronizzarsi con un oggetto in un altro thread per trasmettergli alcune informazioni, eventi o attività. Nei precedenti tutorial di programmazione multi-thread, abbiamo imparato come risolvere il problema produttore-consumatore utilizzando i metodi wait and notify e BlockingQueue . Ora impareremo come applicare il modello produttore-consumatore utilizzando SynchronousQueue. Questa classe supporta inoltre un comportamento corretto per ordinare le attese dei thread produttore e consumatore. Per impostazione predefinita, questo ordinamento non è garantito. Tuttavia, le code create con proprietà corrette garantiscono l'accesso ai thread in una coda FIFO (Firs In First Out).
Produttore/consumatore che utilizza SynchronousQueue in Java.
Esempio SynchronousQueue in Java - risoluzione del problema Producer Consumer - 1 Come ho detto sopra, non c'è niente di meglio del problema produttore-consumatore per comprendere la comunicazione tra thread in qualsiasi linguaggio di programmazione. In questo problema, un thread funge da produttore che produce eventi e attività e l'altro thread funge da consumatore. Un buffer condiviso viene utilizzato per trasferire i dati dal produttore al consumatore. La difficoltà di risolvere questo problema arriva in casi estremi, ad esempio, quando il produttore è costretto ad aspettare perché... il buffer è pieno o il consumatore è costretto ad aspettare perché il buffer è vuoto. Questo è stato facilmente risolto, perché... La coda di blocco forniva non solo un buffer per l'archiviazione dei dati, ma anche il controllo del flusso, bloccando il thread che chiamava il metodo put() (Produttore) se il buffer era pieno e bloccando il thread che chiamava il metodo take() (Consumatore) se il il buffer era vuoto. Ora risolveremo lo stesso problema utilizzando SynchronousQueue, un tipo speciale di raccolte parallele con capacità zero. Nell'esempio seguente, abbiamo due thread chiamati PRODUCER e CONSUMER (dare sempre nomi ai thread, questo è un ottimo stile di programmazione multi-thread). Il primo thread pubblica il punteggio nel gioco, mentre il secondo lo consuma. Il punteggio nel gioco non è altro che un oggetto di tipo String. Ma se esegui il programma con un tipo diverso, non noterai alcuna differenza. Per capire come funziona SynchronousQueue e come risolvere il problema produttore-consumatore, è necessario: eseguire il programma per il debug (debug) nell'ambiente Eclipse o semplicemente avviare il thread produttore commentando consumer.start(); se il thread consumatore non è in esecuzione, il thread produttore verrà bloccato in coda.put(event); se in esecuzione, non sarai in grado di vedere il produttore [PRODUCER] che pubblica l'evento :FOUR. Questo accade perché comportamento specifico di SynchronousQueue, che garantisce che il thread che pubblica i dati si bloccherà finché un altro thread non prenderà i dati e viceversa. Puoi testare il resto del codice commentando producer.start(); e avviando solo il thread del consumatore. Se studi attentamente ciò che il programma restituisce, noterai che l'ordine di output è invertito. Sembra che il thread [CONSUMER] abbia preso i dati prima che il thread [PRODUCER] li producesse. Questo perché SynchronousQueue non garantisce l'accodamento per impostazione predefinita. Ma ha regole di equità che impostano l'accesso ai thread in ordine FIFO. Puoi abilitare queste regole passando true al costruttore SynchronousQueue sovraccaricato in questo modo: import java.util.concurrent.SynchronousQueue; /** * Java Program to solve Producer Consumer problem using SynchronousQueue. A * call to put() will block until there is a corresponding thread to take() that * element. * * @author Javin Paul */ public class SynchronousQueueDemo{ public static void main(String args[]) { final SynchronousQueue queue = new SynchronousQueue (); Thread producer = new Thread("PRODUCER") { public void run() { String event = "FOUR"; try { queue.put(event); // thread will block here System.out.printf("[%s] published event : %s %n", Thread .currentThread() .getName(), event); } catch (InterruptedException e) { e.printStackTrace(); } } }; producer.start(); // starting publisher thread Thread consumer = new Thread("CONSUMER") { public void run() { try { String event = queue.take(); // thread will block here System.out.printf("[%s] consumed event : %s %n", Thread .currentThread() .getName(), event); } catch (InterruptedException e) { e.printStackTrace(); } } }; consumer.start(); // starting consumer thread } } Output: [CONSUMER] consumed event : FOUR [PRODUCER] published event : FOUR new SynchronousQueue(boolean fair).
Cosa devi ricordare su SynchronousQueue in Java.

Ecco alcune proprietà importanti di questo tipo speciale di coda di blocco in Java. È molto utile passare i dati da un thread all'altro in modo sincronizzato. Questa coda non ha capacità e viene bloccata finché un altro thread non la libera.

  1. SynchronousQueue si blocca e finché un thread non è pronto a prendere i dati, un altro proverà a inserirli.
  2. SynchronousQueue non ha volume. Cioè, non contiene dati.
  3. SynchronousQueue viene utilizzato per implementare una strategia di accodamento in avanti, in cui un thread passa il controllo a un thread in attesa o ne crea uno nuovo se consentito, altrimenti il ​​controllo non viene trasferito.
  4. Questa coda non consente dati nulli. Un tentativo di aggiungere un elemento null genererà una NullPointerException .
  5. Se utilizzi altri metodi da Collection (come contiene), SynchronousQueue si comporta come una raccolta vuota.
  6. Non puoi utilizzare il metodo peek di SynchronousQueue perché l'elemento esiste solo quando provi a rimuoverlo; Inoltre, non sarai in grado di inserire elementi (utilizzando qualsiasi metodo) finché un altro thread non tenterà di rimuoverlo.
  7. Non sarai in grado di utilizzare iteratore per SynchronousQueue perché... non ha elementi.
  8. SynchronousQueue può essere creato con regole giuste, dove l'accesso ai thread è garantito in ordine FIFO.
Forse è tutto basato su SynchronousQueue in Java. Abbiamo esaminato alcune delle caratteristiche speciali di questa raccolta multi-thread e abbiamo imparato come risolvere il classico problema produttore-consumatore utilizzando SynchronousQueue in Java. A proposito, chiamarla Coda non è del tutto corretto, perché... non contiene elementi. La chiamata a put() non verrà completata finché un altro thread non chiamerà take(). È più corretto pensarlo come un luogo di incontro di fili, dove condividono un oggetto. In altre parole si tratta di un'utilità per il passaggio sincronizzato di oggetti in Java, forse un'alternativa più sicura al metodo wait and notify .
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION