java synchronized what is thread synchronization java
Questo tutorial spiega la sincronizzazione dei thread in Java insieme a concetti correlati come Java Lock, Race Condition, Mutex, Java Volatile e Deadlock in Java:
In un ambiente multithreading in cui sono coinvolti più thread, è inevitabile che si verifichino conflitti quando più di un thread tenta di ottenere la stessa risorsa contemporaneamente. Questi conflitti provocano una 'condizione di gara' e quindi il programma produce risultati inaspettati.
Per esempio, un singolo file viene aggiornato da due thread. Se un thread T1 è in fase di aggiornamento di questo file, dire una variabile. Ora, mentre questo aggiornamento di T1 è ancora in corso, supponiamo che anche il secondo thread T2 aggiorni la stessa variabile. In questo modo la variabile darà risultati errati.
=> Guarda qui la serie completa di formazione Java.
Quando sono coinvolti più thread, è necessario gestirli in modo tale che una risorsa possa essere utilizzata da un singolo thread alla volta. Nell'esempio precedente, il file a cui si accede da entrambi i thread deve essere gestito in modo tale che T2 non possa accedere al file finché T1 non ha finito di accedervi.
Questo viene fatto in Java utilizzando ' Sincronizzazione dei thread '.
Cosa imparerai:
- Sincronizzazione dei thread in Java
- Multi-threading senza sincronizzazione
- Multi-threading con sincronizzazione
- Conclusione
Sincronizzazione dei thread in Java
Poiché Java è un linguaggio multi_thread, la sincronizzazione dei thread ha molta importanza in Java poiché più thread vengono eseguiti in parallelo in un'applicazione.
Usiamo parole chiave 'Sincronizzato' e 'volatile' per ottenere la sincronizzazione in Java
Abbiamo bisogno della sincronizzazione quando l'oggetto o la risorsa condivisa è mutabile. Se la risorsa è immutabile, i thread leggeranno la risorsa solo contemporaneamente o singolarmente.
In questo caso, non è necessario sincronizzare la risorsa. In questo caso, JVM lo garantisce Il codice sincronizzato Java viene eseguito da un thread alla volta .
La maggior parte delle volte, l'accesso simultaneo alle risorse condivise in Java può introdurre errori come 'Incoerenza della memoria' e 'interferenza del thread'. Per evitare questi errori dobbiamo andare per la sincronizzazione delle risorse condivise in modo che l'accesso a queste risorse si escluda a vicenda.
Usiamo un concetto chiamato Monitor per implementare la sincronizzazione. È possibile accedere a un monitor da un solo thread alla volta. Quando un thread ottiene il blocco, quindi, possiamo dire che il thread è entrato nel monitor.
Quando si accede a un monitor da un thread particolare, il monitor viene bloccato e tutti gli altri thread che tentano di entrare nel monitor vengono sospesi fino a quando il thread di accesso termina e rilascia il blocco.
Andando avanti, discuteremo in dettaglio la sincronizzazione in Java in questo tutorial. Ora, discutiamo alcuni concetti di base relativi alla sincronizzazione in Java.
Condizioni di gara in Java
In un ambiente multithread, quando più di un thread tenta di accedere a una risorsa condivisa per la scrittura contemporaneamente, più thread si sfidano per completare l'accesso alla risorsa. Questo dà origine alla 'condizione di gara'.
Una cosa da considerare è che non ci sono problemi se più thread stanno tentando di accedere a una risorsa condivisa solo per la lettura. Il problema sorge quando più thread accedono contemporaneamente alla stessa risorsa.
Le race condition si verificano a causa della mancanza di una corretta sincronizzazione dei thread nel programma. Quando sincronizziamo correttamente i thread in modo tale che alla volta solo un thread accederà alla risorsa e la condizione di competizione cessa di esistere.
Quindi come rileviamo le condizioni di gara?
Il modo migliore per rilevare la condizione di competizione è la revisione del codice. In qualità di programmatore, dovremmo rivedere attentamente il codice per verificare potenziali condizioni di competizione che potrebbero verificarsi.
Blocchi / monitor in Java
Abbiamo già detto che utilizziamo monitor o blocchi per implementare la sincronizzazione. Il monitor o il blocco è un'entità interna ed è associato a ogni oggetto. Quindi, ogni volta che un thread ha bisogno di accedere all'oggetto, deve prima acquisire il blocco o il monitor del suo oggetto, lavorare sull'oggetto e quindi rilasciare il blocco.
I blocchi in Java appariranno come mostrato di seguito:
public class Lock { private boolean isLocked = false; public synchronized void lock() throws InterruptedException { while(isLocked) { wait(); } isLocked = true; } public synchronized void unlock(){ isLocked = false; notify(); } }
Come mostrato sopra, abbiamo un metodo lock () che blocca l'istanza. Tutti i thread che chiamano il metodo lock () saranno bloccati fino a quando i set di metodi unblock () non saranno bloccati come flag false e notificheranno tutti i thread in attesa.
Alcuni suggerimenti da ricordare sui blocchi:
- In Java, ogni oggetto ha un blocco o un monitor. È possibile accedere a questo blocco tramite un thread.
- Un solo thread alla volta può acquisire questo monitor o blocco.
- Il linguaggio di programmazione Java fornisce una parola chiave Synchronized 'che ci consente di sincronizzare i thread rendendo un blocco o un metodo come Synchronized.
- Le risorse condivise a cui i thread devono accedere vengono mantenute in questo blocco / metodo sincronizzato.
Mutex in Java
Abbiamo già discusso che in un ambiente multithread, possono verificarsi condizioni di competizione quando più di un thread tenta di accedere simultaneamente alle risorse condivise e le condizioni di competizione producono un output imprevisto.
La parte del programma che tenta di accedere alla risorsa condivisa è chiamata 'Sezione critica' . Per evitare il verificarsi di condizioni di competizione, è necessario sincronizzare l'accesso alla sezione critica. Sincronizzando questa sezione critica, ci assicuriamo che solo un thread alla volta possa accedere alla sezione critica.
Il tipo più semplice di sincronizzatore è il 'mutex'. Mutex garantisce che, in ogni istanza, solo un thread possa eseguire la sezione critica.
Il mutex è simile al concetto di monitor o lock di cui abbiamo discusso sopra. Se un thread deve accedere a una sezione critica, deve acquisire il mutex. Una volta acquisito il mutex, il thread accederà al codice della sezione critica e, al termine, rilascerà il mutex.
Gli altri thread in attesa di accedere alla sezione critica verranno nel frattempo bloccati. Non appena il thread che contiene mutex lo rilascia, un altro thread entrerà nella sezione critica.
dichiarare un array di oggetti in java
Esistono diversi modi in cui possiamo implementare un mutex in Java.
- Utilizzo della parola chiave sincronizzata
- Utilizzando Semaphore
- Utilizzando ReentrantLock
In questo tutorial, discuteremo il primo approccio, ovvero la sincronizzazione. Gli altri due approcci - Semaphore e ReentrantLock saranno discussi nel prossimo tutorial in cui discuteremo del pacchetto concorrente java.
Parola chiave sincronizzata
Java fornisce una parola chiave 'sincronizzata' che può essere utilizzata in un programma per contrassegnare una sezione critica. La sezione critica può essere un blocco di codice o un metodo completo. Pertanto, solo un thread può accedere alla sezione critica contrassegnata dalla parola chiave Synchronized.
Possiamo scrivere le parti simultanee (parti che vengono eseguite contemporaneamente) per un'applicazione utilizzando la parola chiave Synchronized. Ci liberiamo anche delle condizioni di gara creando un blocco di codice o un metodo Sincronizzato.
Quando contrassegniamo un blocco o un metodo come sincronizzato, proteggiamo le risorse condivise all'interno di queste entità dall'accesso simultaneo e quindi dalla corruzione.
Tipi di sincronizzazione
Esistono 2 tipi di sincronizzazione come spiegato di seguito:
# 1) Sincronizzazione dei processi
La sincronizzazione dei processi coinvolge più processi o thread eseguiti contemporaneamente. Alla fine raggiungono uno stato in cui questi processi o thread si impegnano in una sequenza specifica di azioni.
# 2) Sincronizzazione dei thread
In Thread Synchronization, più di un thread sta tentando di accedere a uno spazio condiviso. I thread sono sincronizzati in modo tale che lo spazio condiviso sia accessibile solo da un thread alla volta.
La sincronizzazione del processo non rientra nell'ambito di questo tutorial. Quindi qui discuteremo solo la sincronizzazione dei thread.
In Java, possiamo utilizzare la parola chiave sincronizzata con:
- Un blocco di codice
- Un metodo
I tipi precedenti sono i tipi di sincronizzazione dei thread che si escludono a vicenda. L'esclusione reciproca impedisce ai thread che accedono ai dati condivisi di interferire tra loro.
L'altro tipo di sincronizzazione dei thread è la 'comunicazione InterThread' che si basa sulla cooperazione tra i thread. La comunicazione Interthread non rientra nello scopo di questo tutorial.
Prima di procedere con la sincronizzazione di blocchi e metodi, implementiamo un programma Java per dimostrare il comportamento dei thread in assenza di sincronizzazione.
Multi-threading senza sincronizzazione
Il seguente programma Java ha più thread che non sono sincronizzati.
class PrintCount { //method to print the thread counter public void printcounter() { try { for(int i = 5; i > 0; i--) { System.out.println('Counter ==> ' + i ); } } catch (Exception e) { System.out.println('Thread interrupted.'); } } } //thread class class ThreadCounter extends Thread { private Thread t; private String threadName; PrintCount PD; //class constructor for initialization ThreadCounter( String name, PrintCount pd) { threadName = name; PD = pd; } //run method for thread public void run() { PD.printcounter(); System.out.println('Thread ' + threadName + ' exiting.'); } //start method for thread public void start () { System.out.println('Starting ' + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class Main { public static void main(String args()) { PrintCount PD = new PrintCount(); //create two instances of thread class ThreadCounter T1 = new ThreadCounter( 'ThreadCounter_1 ', PD ); ThreadCounter T2 = new ThreadCounter( 'ThreadCounter_2 ', PD ); //start both the threads T1.start(); T2.start(); // wait for threads to end try { T1.join(); T2.join(); } catch ( Exception e) { System.out.println('Interrupted'); } } }
Produzione
Dall'output, possiamo vedere che poiché i thread non sono sincronizzati, l'output è incoerente. Entrambi i thread iniziano e quindi visualizzano il contatore uno dopo l'altro. Entrambi i fili escono alla fine.
Dal programma dato, il primo thread dovrebbe essere terminato dopo aver visualizzato i valori del contatore, quindi il secondo thread avrebbe dovuto iniziare a visualizzare i valori del contatore.
Ora passiamo alla sincronizzazione e iniziamo con la sincronizzazione del blocco di codice.
Blocco codice sincronizzato
Un blocco sincronizzato viene utilizzato per sincronizzare un blocco di codice. Questo blocco di solito è composto da poche righe. Un blocco sincronizzato viene utilizzato quando non si desidera sincronizzare un intero metodo.
Per esempio, abbiamo un metodo con diciamo 75 righe di codice. Di questo, solo 10 righe di codice devono essere eseguite da un thread alla volta. In questo caso, se rendiamo sincronizzato l'intero metodo, sarà un peso per il sistema. In tali situazioni, andiamo per blocchi sincronizzati.
L'ambito del metodo sincronizzato è sempre inferiore a quello di un metodo sincronizzato. Un metodo sincronizzato blocca un oggetto di una risorsa condivisa che deve essere utilizzata da più thread.
La sintassi generale di un blocco sincronizzato è la seguente:
synchronized (lock_object){ //synchronized code statements }
Qui 'lock_object' è un'espressione di riferimento a un oggetto su cui si desidera ottenere il blocco. Quindi, ogni volta che un thread vuole accedere alle istruzioni sincronizzate all'interno del blocco per l'esecuzione, deve acquisire il blocco sul monitor 'lock_object'.
Come già discusso, la parola chiave sincronizzata garantisce che un solo thread possa acquisire un blocco alla volta e che tutti gli altri thread debbano attendere che il thread che contiene il blocco termini e rilasci il blocco.
qa intervista domande e risposte pdf
Nota
- Se il lock_object utilizzato è Null, viene generata una 'NullPointerException'.
- Se un thread dorme mentre si tiene ancora il blocco, il blocco non viene rilasciato. Gli altri thread non saranno in grado di accedere all'oggetto condiviso durante questo periodo di sospensione.
Ora presenteremo l'esempio sopra che è stato già implementato con lievi modifiche. Nel programma precedente, non abbiamo sincronizzato il codice. Ora useremo il blocco sincronizzato e confronteremo l'output.
Multi-threading con sincronizzazione
Nel programma Java di seguito, utilizziamo un blocco sincronizzato. Nel metodo run, sincronizziamo il codice delle righe che stampano il contatore per ogni thread.
class PrintCount { //print thread counter public void printCounter() { try { for(int i = 5; i > 0; i--) { System.out.println('Counter ==> ' + i ); } } catch (Exception e) { System.out.println('Thread interrupted.'); } } } //thread class class ThreadCounter extends Thread { private Thread t; private String threadName; PrintCount PD; //class constructor for initialization ThreadCounter( String name, PrintCount pd) { threadName = name; PD = pd; } //run () method for thread with synchronized block public void run() { synchronized(PD) { PD.printCounter(); } System.out.println('Thread ' + threadName + ' exiting.'); } //start () method for thread public void start () { System.out.println('Starting ' + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class Main { public static void main(String args()) { PrintCount PD = new PrintCount(); //create thread instances ThreadCounter T1 = new ThreadCounter( 'Thread_1 ', PD ); ThreadCounter T2 = new ThreadCounter( 'Thread_2 ', PD ); //start both the threads T1.start(); T2.start(); // wait for threads to end try { T1.join(); T2.join(); } catch ( Exception e) { System.out.println('Interrupted'); } } }
Produzione
Ora l'output di questo programma che utilizza il blocco sincronizzato è abbastanza coerente. Come previsto, entrambi i thread iniziano l'esecuzione. Il primo thread ha terminato di visualizzare i valori del contatore ed è uscito. Quindi il secondo thread visualizza i valori del contatore ed esce.
Metodo sincronizzato
Discutiamo il metodo sincronizzato in questa sezione. In precedenza abbiamo visto che possiamo dichiarare un piccolo blocco composto da meno righe di codice come blocco sincronizzato. Se vogliamo che l'intera funzione sia sincronizzata, possiamo dichiarare un metodo come sincronizzato.
Quando un metodo viene sincronizzato, solo un thread alla volta sarà in grado di effettuare una chiamata al metodo.
La sintassi generale per scrivere un metodo sincronizzato è:
synchronized method_name (parameters){ //synchronized code }
Proprio come un blocco sincronizzato, nel caso di un metodo sincronizzato, abbiamo bisogno di un lock_object che verrà utilizzato dai thread che accedono al metodo sincronizzato.
Per il metodo sincronizzato, l'oggetto blocco può essere uno dei seguenti:
- Se il metodo sincronizzato è statico, l'oggetto lock è dato dall'oggetto '.class'.
- Per un metodo non statico, l'oggetto di blocco è dato dall'oggetto corrente, ovvero l'oggetto 'questo'.
Una caratteristica peculiare della parola chiave sincronizzata è che è rientrata. Ciò significa che un metodo sincronizzato può chiamare un altro metodo sincronizzato con lo stesso blocco. Quindi un thread che detiene il blocco può accedere a un altro metodo sincronizzato senza dover acquisire un blocco diverso.
Il metodo sincronizzato viene dimostrato utilizzando l'esempio seguente.
class NumberClass { //synchronized method to print squares of numbers synchronized void printSquares(int n) throws InterruptedException { //iterate from 1 to given number and print the squares at each iteration for (int i = 1; i <= n; i++) { System.out.println(Thread.currentThread().getName() + ' :: '+ i*i); Thread.sleep(500); } } } public class Main { public static void main(String args()) { final NumberClass number = new NumberClass(); //create thread Runnable thread = new Runnable() { public void run() { try { number.printSquares(3); } catch (InterruptedException e) { e.printStackTrace(); } } }; //start thread instance new Thread(thread, 'Thread One').start(); new Thread(thread, 'Thread Two').start(); } }
Produzione
Nel programma sopra, abbiamo utilizzato un metodo sincronizzato per stampare i quadrati di un numero. Il limite superiore del numero viene passato al metodo come argomento. Quindi, a partire da 1, vengono stampati i quadrati di ogni numero fino al raggiungimento del limite superiore.
Nella funzione main, viene creata l'istanza del thread. A ogni istanza di thread viene passato un numero per stampare i quadrati.
Come accennato in precedenza, quando un metodo da sincronizzare è statico, l'oggetto lock è coinvolto nella classe e non nell'oggetto. Ciò significa che bloccheremo la classe e non l'oggetto. Questa è chiamata sincronizzazione statica.
Di seguito viene fornito un altro esempio.
class Table{ //synchronized static method to print squares of numbers synchronized static void printTable(int n){ for(int i=1;i<=10;i++){ System.out.print(n*i + ' '); try{ Thread.sleep(400); }catch(Exception e){} } System.out.println(); } } //thread class Thread_One class Thread_One extends Thread{ public void run(){ Table.printTable(2); } } //thread class Thread_Two class Thread_Two extends Thread{ public void run(){ Table.printTable(5); } } public class Main{ public static void main(String t()){ //create instances of Thread_One and Thread_Two Thread_One t1=new Thread_One (); Thread_Two t2=new Thread_Two (); //start each thread instance t1.start(); t2.start(); } }
Produzione
Nel programma sopra, stampiamo le tabelline dei numeri. Ogni numero la cui tabella deve essere stampata è un'istanza di thread di una classe di thread diversa. Quindi stampiamo le tabelline di 2 e 5, quindi abbiamo thread_one e thread_two di due classi per stampare le tabelle 2 e 5 rispettivamente.
Per riassumere, la parola chiave sincronizzata di Java esegue le seguenti funzioni:
- La parola chiave sincronizzata in Java garantisce l'accesso mutuamente esclusivo alle risorse condivise fornendo un meccanismo di blocco. Il blocco impedisce anche le condizioni di gara.
- Utilizzando la parola chiave sincronizzata, evitiamo errori di programmazione simultanei nel codice.
- Quando un metodo o un blocco viene dichiarato come sincronizzato, un thread necessita di un blocco esclusivo per accedere al metodo o blocco sincronizzato. Dopo aver eseguito le azioni necessarie, il thread rilascia il blocco e svuota l'operazione di scrittura. In questo modo eliminerà gli errori di memoria legati all'inconsistenza.
Volatile in Java
Una parola chiave volatile in Java viene utilizzata per rendere le classi thread-safe. Usiamo anche la parola chiave volatile per modificare il valore della variabile da diversi thread. Una parola chiave volatile può essere utilizzata per dichiarare una variabile con tipi primitivi oltre che oggetti.
In alcuni casi, una parola chiave volatile viene utilizzata come alternativa alla parola chiave sincronizzata, ma si noti che non sostituisce la parola chiave sincronizzata.
Quando una variabile viene dichiarata volatile, il suo valore non viene mai memorizzato nella cache ma viene sempre letto dalla memoria principale. Una variabile volatile garantisce ordini e visibilità. Sebbene una variabile possa essere dichiarata come volatile, non possiamo dichiarare classi o metodi come volatili.
Considera il seguente blocco di codice:
class ABC{ static volatile int myvar =10; }
Nel codice sopra, la variabile myvar è statica e volatile. Una variabile statica è condivisa tra tutti gli oggetti della classe. La variabile volatile risiede sempre nella memoria principale e non viene mai memorizzata nella cache.
Quindi ci sarà solo una copia di myvar nella memoria principale e tutte le azioni di lettura / scrittura verranno eseguite su questa variabile dalla memoria principale. Se myvar non fosse dichiarato volatile, ogni oggetto thread avrebbe una copia diversa che comporterebbe incongruenze.
Di seguito sono elencate alcune delle differenze tra le parole chiave volatili e sincronizzate.
Parola chiave volatile | Parola chiave sincronizzata |
---|---|
La parola chiave volatile viene utilizzata solo con le variabili. | La parola chiave sincronizzata viene utilizzata con blocchi di codice e metodi. |
Una parola chiave volatile non può bloccare il thread in attesa. | La parola chiave sincronizzata può bloccare il thread in attesa. |
Le prestazioni dei thread sono migliorate con Volatile. | Le prestazioni del thread peggiorano leggermente con la sincronizzazione. |
Le variabili volatili risiedono nella memoria principale. | I costrutti sincronizzati non risiedono nella memoria principale. |
Volatile sincronizza una variabile alla volta tra la memoria del thread e la memoria principale. | La parola chiave sincronizzata sincronizza tutte le variabili contemporaneamente. |
Deadlock in Java
Abbiamo visto che possiamo sincronizzare più thread usando la parola chiave sincronizzata e rendere i programmi thread-safe. Sincronizzando i thread, ci assicuriamo che i thread multipli vengano eseguiti contemporaneamente in un ambiente multi-thread.
Tuttavia, a volte si verifica una situazione in cui i thread non possono più funzionare contemporaneamente. Invece, aspettano all'infinito. Ciò si verifica quando un thread attende una risorsa e quella risorsa viene bloccata dal secondo thread.
Il secondo thread, invece, è in attesa della risorsa bloccata dal primo thread. Una situazione del genere provoca un 'deadlock' in Java.
Deadlock in Java è rappresentato utilizzando l'immagine sottostante.
Come possiamo vedere dal diagramma sopra, il thread A ha bloccato la risorsa r1 ed è in attesa della risorsa r2. Il thread B, d'altra parte, ha bloccato la risorsa r2 ed è in attesa su r1.
Quindi nessuno dei thread può terminare la propria esecuzione a meno che non si impossessi delle risorse in sospeso. Questa situazione ha provocato il blocco critico (deadlock) in cui entrambi i thread attendono all'infinito le risorse.
Di seguito è riportato un esempio di deadlock in Java.
public class Main { public static void main(String() args) { //define shared resources final String shared_res1 = 'Java tutorials'; final String shared_res2 = 'Multithreading'; // thread_one => locks shared_res1 then shared_res2 Thread thread_one = new Thread() { public void run() { synchronized (shared_res1) { System.out.println('Thread one: locked shared resource 1'); try { Thread.sleep(100);} catch (Exception e) {} synchronized (shared_res2) { System.out.println('Thread one: locked shared resource 2'); } } } }; // thread_two=> locks shared_res2 then shared_res1 Thread thread_two = new Thread() { public void run() { synchronized (shared_res2) { System.out.println('Thread two: locked shared resource 2'); try { Thread.sleep(100);} catch (Exception e) {} synchronized (shared_res1) { System.out.println('Thread two: locked shared resource 1'); } } } }; //start both the threads thread_one.start(); thread_two.start(); } }
Produzione
Nel programma sopra, abbiamo due risorse condivise e due thread. Entrambi i thread tentano di accedere alle risorse condivise uno per uno. L'output mostra entrambi i thread che bloccano una risorsa ciascuno in attesa degli altri. In tal modo creando una situazione di stallo.
Sebbene non possiamo impedire che si verifichino completamente situazioni di deadlock, possiamo certamente evitarle adottando alcuni passaggi.
Di seguito sono elencati i mezzi che consentono di evitare deadlock in Java.
# 1) Evitando i blocchi annidati
La presenza di blocchi annidati è il motivo più importante per i deadlock. I blocchi annidati sono i blocchi assegnati a più thread. Quindi dovremmo evitare di dare blocchi a più di un thread.
# 2) Usa il thread Join
Dovremmo usare Thread.join con il tempo massimo in modo che i thread possano utilizzare il tempo massimo per l'esecuzione. Ciò impedirà il deadlock che si verifica principalmente quando un thread attende continuamente gli altri.
# 3) Evita il blocco non necessario
Dobbiamo bloccare solo il codice necessario. Avere blocchi non necessari per il codice può causare deadlock nel programma. Poiché i deadlock possono rompere il codice e ostacolare il flusso del programma, dovremmo essere inclini a evitare deadlock nei nostri programmi.
Domande frequenti
D # 1) Che cos'è la sincronizzazione e perché è importante?
Risposta: La sincronizzazione è il processo di controllo dell'accesso di una risorsa condivisa a più thread. Senza sincronizzazione, più thread possono aggiornare o modificare la risorsa condivisa contemporaneamente, con conseguenti incongruenze.
Quindi dovremmo assicurarci che in un ambiente multi-thread, i thread siano sincronizzati in modo che il modo in cui accedono alle risorse condivise sia reciprocamente esclusivo e coerente.
D # 2) Che cos'è la sincronizzazione e la non sincronizzazione in Java?
Risposta: La sincronizzazione significa che un costrutto è thread-safe. Ciò significa che più thread non possono accedere al costrutto (blocco di codice, metodo, ecc.) Contemporaneamente.
I costrutti non sincronizzati non sono thread-safe. Più thread possono accedere a metodi o blocchi non sincronizzati in qualsiasi momento. Una popolare classe non sincronizzata in Java è StringBuilder.
D # 3) Perché è necessaria la sincronizzazione?
Risposta: Quando i processi devono essere eseguiti contemporaneamente, è necessaria la sincronizzazione. Questo perché abbiamo bisogno di risorse che possono essere condivise tra molti processi.
Per evitare conflitti tra processi o thread per l'accesso alle risorse condivise, è necessario sincronizzare queste risorse in modo che tutti i thread abbiano accesso alle risorse e anche l'applicazione funzioni senza problemi.
D # 4) Come si ottiene un ArrayList sincronizzato?
Risposta: Possiamo usare il metodo di elenco Collections.synchronized con ArrayList come argomento per convertire ArrayList in un elenco sincronizzato.
D # 5) HashMap è sincronizzato?
miglior software per il recupero di file cancellati
Risposta: No, HashMap non è sincronizzato ma HashTable è sincronizzato.
Conclusione
In questo tutorial, abbiamo discusso in dettaglio la sincronizzazione dei thread. Insieme ad esso, abbiamo anche imparato a conoscere la parola chiave volatile e i deadlock in Java. La sincronizzazione consiste nella sincronizzazione del processo e del thread.
In un ambiente multithread, siamo più interessati alla sincronizzazione dei thread. Abbiamo visto l'approccio con parole chiave sincronizzate della sincronizzazione dei thread qui.
Deadlock è una situazione in cui più thread aspettano continuamente le risorse. Abbiamo visto l'esempio dei deadlock in Java insieme ai metodi per evitare i deadlock in Java.
=> Visita qui per imparare Java da zero.
Lettura consigliata
- Thread.Sleep () - Metodo Thread Sleep () in Java con esempi
- Thread Java con metodi e ciclo di vita
- Nozioni di base su Java: sintassi Java, classe Java e concetti principali di Java
- Multithreading in Java - Tutorial con esempi
- Multithreading in C ++ con esempi
- Tutorial JAVA per principianti: oltre 100 tutorial video Java pratici
- Componenti Java: piattaforma Java, JDK, JRE e Java Virtual Machine
- Tutorial Java String | Metodi Java String con esempi