CodeGym /Corsi /All lectures for IT purposes /Libreria di concorrenza Java

Libreria di concorrenza Java

All lectures for IT purposes
Livello 1, Lezione 425
Disponibile

Multithread in Java

La Java Virtual Machine supporta il calcolo parallelo . Tutti i calcoli possono essere eseguiti nel contesto di uno o più thread. Possiamo facilmente configurare l'accesso alla stessa risorsa o oggetto per più thread, nonché configurare un thread per eseguire un singolo blocco di codice.

Qualsiasi sviluppatore deve sincronizzare il lavoro con i thread durante le operazioni di lettura e scrittura per le risorse a cui sono allocati più thread.

È importante che al momento dell'accesso alla risorsa si disponga di dati aggiornati in modo che un altro thread possa modificarli e ottenere le informazioni più aggiornate. Anche se prendiamo l'esempio di un conto corrente bancario, fino a quando non ci sono arrivati ​​i soldi, non puoi usarlo, quindi è importante avere sempre dati aggiornati. Java ha classi speciali per la sincronizzazione e la gestione dei thread.

Infila gli oggetti

Tutto inizia con il thread principale (principale), ovvero almeno il tuo programma ha già un thread in esecuzione. Il thread principale può creare altri thread utilizzando Callable o Runnable . La creazione differisce solo nel risultato restituito, Runnable non restituisce un risultato e non può generare un'eccezione verificata. Pertanto, hai una buona opportunità per creare un lavoro efficiente con i file, ma questo è molto pericoloso e devi stare attento.

È anche possibile pianificare l'esecuzione del thread su un core della CPU separato. Il sistema può facilmente spostarsi tra i thread ed eseguire un thread specifico con le giuste impostazioni: ovvero, il thread che legge i dati viene eseguito per primo, non appena abbiamo i dati, quindi li passiamo al thread che è responsabile della convalida, dopodiché lo passiamo al thread per eseguire alcune logiche di business e un nuovo thread le riscrive. In una situazione del genere, 4 thread elaborano i dati a turno e tutto funzionerà più velocemente di un thread. Ognuno di questi flussi viene convertito in un flusso del sistema operativo nativo, ma il modo in cui verrà convertito dipende dall'implementazione JVM.

La classe Thread viene utilizzata per creare e lavorare con i thread. Ha meccanismi di controllo standard, oltre a quelli astratti, come classi e raccolte da java.util.concurrent .

Sincronizzazione dei thread in Java

La comunicazione viene fornita condividendo l'accesso agli oggetti. Questo è molto efficace, ma allo stesso tempo è molto facile commettere un errore durante il lavoro. Gli errori si verificano in due casi: interferenza del thread - quando un altro thread interferisce con il tuo thread ed errori di coerenza della memoria - coerenza della memoria. Per risolvere e prevenire questi errori, abbiamo diversi metodi di sincronizzazione.

La sincronizzazione dei thread in Java è gestita dai monitor, questo è un meccanismo di alto livello che consente a un solo thread di eseguire un blocco di codice protetto dallo stesso monitor alla volta. Il comportamento dei monitor è considerato in termini di blocchi; un monitor - un lucchetto.

La sincronizzazione ha diversi punti importanti a cui devi prestare attenzione. Il primo punto è l'esclusione reciproca: solo un thread può possedere il monitor, quindi la sincronizzazione sul monitor implica che una volta che un thread entra in un blocco sincronizzato protetto dal monitor, nessun altro thread può entrare nel blocco protetto dal monitor. il primo thread esce dal blocco sincronizzato. Cioè, più thread non possono accedere contemporaneamente allo stesso blocco sincronizzato.

Ma la sincronizzazione non è solo mutua esclusione. La sincronizzazione garantisce che i dati scritti in memoria prima o all'interno di un blocco sincronizzato diventino visibili ad altri thread sincronizzati sullo stesso monitor. Dopo essere usciti dal blocco, rilasciamo il monitor e un altro thread può prenderlo e avviare l'esecuzione di questo blocco di codice.

Quando un nuovo thread acquisisce il monitor, otteniamo l'accesso e la possibilità di eseguire quel blocco di codice, e in quel momento le variabili verranno caricate dalla memoria principale. Quindi possiamo vedere tutte le voci rese visibili dalla versione precedente del monitor.

Una singola lettura o scrittura di un campo è atomica se il campo è dichiarato volatile (per long e double questo è importante) oppure se tutti gli accessi al campo sono protetti dallo stesso lock. Senza sincronizzazione sono possibili effetti di riordinamento (reordering): in un programma sincronizzato in modo errato, un thread può vedere le modifiche fatte da un altro thread in un ordine inatteso.

L'effetto di mutua esclusione e sincronizzazione dei thread, ovvero il loro corretto funzionamento, si ottiene solo inserendo un blocco o un metodo sincronizzato che acquisisce implicitamente un blocco o ottenendo esplicitamente un blocco. Ne parleremo di seguito. Entrambi i modi di lavorare influenzano la tua memoria ed è importante non dimenticare di lavorare con variabili volatili .

Campi volatili in Java

La parola chiave volatile risolve il problema della visibilità. Se un thread ha scritto un valore in un campo volatile, qualsiasi altro thread che legga quel campo in seguito vedrà il nuovo valore, non una copia obsoleta.

Per l'effetto sulla memoria, la scrittura in un campo volatile è simile al rilascio di un monitor, e la lettura alla sua acquisizione. Tutto ciò che il thread A ha scritto prima di scrivere nel campo volatile è garantito che sia visto dal thread B, se questo ha letto da quel campo il valore scritto. Questa relazione si chiama happens-before («avviene prima»).

Una singola lettura o scrittura di un campo volatile è atomica, anche per long e double. Le operazioni composte, invece, come count++ (leggere, incrementare, scrivere), non lo sono: tra un passo e l'altro può inserirsi un altro thread, e una parte degli incrementi va persa. Con volatile non c'è mutua esclusione. Perché un'operazione composta venga eseguita in modo atomico, servono synchronized, Lock o classi come AtomicInteger, AtomicLong e simili.

Java simultaneo

Se vuoi creare un'applicazione super efficiente e multi-thread, devi usare le classi della libreria JavaConcurrent , che si trovano nel pacchetto java.util.concurrent .

La libreria è molto voluminosa e ha diverse funzionalità, quindi diamo un'occhiata a cosa c'è dentro e dividiamola in alcuni moduli:

Java simultaneo

Concurrent Collections è un insieme di raccolte per lavorare in un ambiente multi-thread. Invece del wrapper di base Collections.synchronizedList con il blocco dell'accesso all'intera raccolta, vengono utilizzati blocchi sui segmenti di dati o algoritmi senza attesa per leggere i dati in parallelo.

Code: code non bloccanti e bloccanti per lavorare in un ambiente multi-thread. Le code non bloccanti si concentrano sulla velocità e sul funzionamento senza bloccare i thread. Le code di blocco sono adatte per lavorare quando è necessario "rallentare" i thread Producer o Consumer . Ad esempio, in una situazione in cui alcune delle condizioni non sono soddisfatte, la coda è vuota o piena o non esiste un consumatore libero 'a.

I sincronizzatori sono utility per la sincronizzazione dei thread. Sono un'arma potente nel calcolo "parallelo".

Executors è un framework per la creazione più comoda e semplice di pool di thread, è facile impostare la pianificazione di attività asincrone con l'ottenimento di risultati.

I blocchi sono molti meccanismi flessibili di sincronizzazione dei thread rispetto ai meccanismi di base sincronizzati , attendere , notificare , notificare .

Gli atomi sono classi che possono supportare operazioni atomiche su primitive e riferimenti.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION