Qualsiasi applicazione può avere più processi (istanze). Ciascuno di questo processo può essere assegnato come thread singolo o più thread. In questo tutorial vedremo come eseguire più attività contemporaneamente e impareremo anche di più sui thread e sulla sincronizzazione tra i thread.
In questo tutorial impareremo:
- Cos'è Single Thread
- Cos'è il multithreading in Java?
- Ciclo di vita del thread in Java
- Sincronizzazione dei thread Java
- Esempio di multithreading Java
Cos'è Single Thread?
Un singolo thread è fondamentalmente un'unità leggera e la più piccola unità di elaborazione. Java utilizza i thread utilizzando una "classe thread".
Esistono due tipi di thread: thread utente e thread daemon (i thread daemon vengono utilizzati quando si desidera pulire l'applicazione e vengono utilizzati in background).
Quando un'applicazione viene avviata per la prima volta, viene creato il thread utente. Dopo questo, possiamo creare molti thread utente e thread daemon.
Esempio di thread singolo:
demotest pacchetto;classe pubblica GuruThread{public static void main (String [] args) {System.out.println ("Single Thread");}}
Vantaggi del filo singolo:
- Riduce l'overhead nell'applicazione poiché un singolo thread viene eseguito nel sistema
- Inoltre, riduce i costi di manutenzione dell'applicazione.
Cos'è il multithreading in Java?
Il MULTITHREADING in Java è un processo di esecuzione simultanea di due o più thread per il massimo utilizzo della CPU. Le applicazioni multithread eseguono due o più thread eseguiti contemporaneamente. Quindi, è anche noto come concorrenza in Java. Ogni thread corre paralleli tra loro. Più thread non allocano un'area di memoria separata, quindi risparmiano memoria. Inoltre, il cambio di contesto tra i thread richiede meno tempo.
Esempio di Multi thread:
demotest pacchetto;la classe pubblica GuruThread1 implementa Runnable{public static void main (String [] args) {Thread guruThread1 = nuovo thread ("Guru1");Thread guruThread2 = nuovo thread ("Guru2");guruThread1.start ();guruThread2.start ();System.out.println ("I nomi dei thread sono i seguenti:");System.out.println (guruThread1.getName ());System.out.println (guruThread2.getName ());}@Oltrepassarepublic void run () {}}
Vantaggi del multithread:
- Gli utenti non sono bloccati perché i thread sono indipendenti e possiamo eseguire più operazioni a volte
- In quanto tali, i thread sono indipendenti, gli altri thread non verranno influenzati se un thread incontra un'eccezione.
Ciclo di vita del thread in Java
Il ciclo di vita di un thread:
Ci sono varie fasi del ciclo di vita del filo come mostrato nel diagramma sopra:
- Nuovo
- Runnable
- In esecuzione
- In attesa
- Morto
- Novità: in questa fase, il thread viene creato utilizzando la classe "Thread class". Rimane in questo stato fino a quando il programma non avvia il thread. È anche noto come filo nato.
- Eseguibile: in questa pagina, l'istanza del thread viene richiamata con un metodo di avvio. Il controllo del thread viene assegnato allo scheduler per terminare l'esecuzione. Dipende dallo scheduler, se eseguire il thread.
- In esecuzione: quando il thread inizia l'esecuzione, lo stato viene modificato in stato "in esecuzione". Lo scheduler seleziona un thread dal pool di thread e inizia l'esecuzione nell'applicazione.
- In attesa: questo è lo stato in cui un thread deve attendere. Poiché nell'applicazione sono in esecuzione più thread, è necessaria la sincronizzazione tra i thread. Quindi, un thread deve attendere, finché l'altro thread non viene eseguito. Pertanto, questo stato viene definito stato di attesa.
- Dead: questo è lo stato in cui il thread viene terminato. Il thread è in esecuzione e non appena ha completato l'elaborazione è in "stato morto".
Alcuni dei metodi comunemente usati per i thread sono:
Metodo | Descrizione |
---|---|
inizio() | Questo metodo avvia l'esecuzione del thread e JVM chiama il metodo run () sul thread. |
Sleep (int millisecondi) | Questo metodo fa dormire il thread, quindi l'esecuzione del thread si fermerà per i millisecondi forniti e successivamente il thread inizierà nuovamente l'esecuzione. Questo aiuto nella sincronizzazione dei thread. |
getName () | Restituisce il nome del thread. |
setPriority (int newpriority) | Cambia la priorità del thread. |
dare la precedenza () | Fa sì che il thread corrente su halt e altri thread vengano eseguiti. |
Esempio: in questo esempio creeremo un thread ed esploreremo i metodi incorporati disponibili per i thread.
demotest pacchetto;public class thread_example1 implementa Runnable {@Oltrepassarepublic void run () {}public static void main (String [] args) {Thread guruthread1 = nuovo Thread ();guruthread1.start ();provare {guruthread1.sleep (1000);} catch (InterructedException e) {// TODO Blocco catch generato automaticamentee.printStackTrace ();}guruthread1.setPriority (1);int gurupriority = guruthread1.getPriority ();System.out.println (gurupriority);System.out.println ("Thread in esecuzione");}}
Spiegazione del codice:
- Riga di codice 2: stiamo creando una classe "thread_Example1" che implementa l'interfaccia Runnable (dovrebbe essere implementata da qualsiasi classe le cui istanze devono essere eseguite dal thread).
- Riga di codice 4: sovrascrive il metodo di esecuzione dell'interfaccia eseguibile poiché è obbligatorio sovrascrivere tale metodo
- Riga di codice 6: Qui abbiamo definito il metodo principale in cui inizieremo l'esecuzione del thread.
- Riga di codice 7: qui stiamo creando un nuovo nome di thread come "guruthread1" istanziando una nuova classe di thread.
- Riga di codice 8: useremo il metodo "start" del thread utilizzando l'istanza "guruthread1". Qui inizierà l'esecuzione del thread.
- Riga di codice 10: qui stiamo usando il metodo "sleep" del thread usando l'istanza "guruthread1". Quindi, il thread dormirà per 1000 millisecondi.
- Codice 9-14: qui abbiamo messo il metodo sleep nel blocco try catch poiché c'è un'eccezione controllata che si verifica cioè eccezione interrotta.
- Riga di codice 15: qui stiamo impostando la priorità del thread su 1 da qualsiasi priorità fosse
- Riga di codice 16: qui stiamo ottenendo la priorità del thread utilizzando getPriority ()
- Riga di codice 17: qui stiamo stampando il valore recuperato da getPriority
- Riga di codice 18: qui stiamo scrivendo un testo che il thread sta eseguendo.
Quando esegui il codice sopra, ottieni il seguente output:
Produzione:
5 è la priorità del thread e Thread Running è il testo che è l'output del nostro codice.
Sincronizzazione dei thread Java
Nel multithreading, c'è il comportamento asincrono dei programmi. Se un thread sta scrivendo alcuni dati e un altro thread che sta leggendo i dati contemporaneamente, potrebbe creare incoerenza nell'applicazione.
Quando è necessario accedere alle risorse condivise da due o più thread, viene utilizzato l'approccio di sincronizzazione.
Java ha fornito metodi sincronizzati per implementare il comportamento sincronizzato.
In questo approccio, una volta che il thread raggiunge all'interno del blocco sincronizzato, nessun altro thread può chiamare quel metodo sullo stesso oggetto. Tutti i thread devono attendere che il thread finisca il blocco sincronizzato e ne esca.
In questo modo, la sincronizzazione aiuta in un'applicazione multithread. Un thread deve attendere che un altro thread termini la sua esecuzione solo allora gli altri thread possono essere eseguiti.
Può essere scritto nella seguente forma:
Sincronizzato (oggetto){// Blocco di istruzioni da sincronizzare}
Esempio di multithreading Java
In questo esempio, prenderemo due thread e recupereremo i nomi del thread.
Esempio 1:
GuruThread1.javademotest pacchetto;public class GuruThread1 implementa Runnable {/ *** @param args* /public static void main (String [] args) {Thread guruThread1 = nuovo thread ("Guru1");Thread guruThread2 = nuovo thread ("Guru2");guruThread1.start ();guruThread2.start ();System.out.println ("I nomi dei thread sono i seguenti:");System.out.println (guruThread1.getName ());System.out.println (guruThread2.getName ());}@Oltrepassarepublic void run () {}}
Spiegazione del codice:
- Riga di codice 3: abbiamo preso una classe "GuruThread1" che implementa Runnable (dovrebbe essere implementata da qualsiasi classe le cui istanze devono essere eseguite dal thread).
- Riga di codice 8: questo è il metodo principale della classe
- Riga di codice 9: qui stiamo istanziando la classe Thread, creando un'istanza denominata "guruThread1" e creando un thread.
- Riga di codice 10: qui stiamo istanziando la classe Thread, creando un'istanza chiamata "guruThread2" e creando un thread.
- Riga di codice 11: Stiamo iniziando il thread, ovvero guruThread1.
- Riga di codice 12: Stiamo iniziando il thread, ovvero guruThread2.
- Riga di codice 13: Emissione del testo come "I nomi dei thread sono i seguenti:"
- Riga di codice 14: ottenere il nome del thread 1 utilizzando il metodo getName () della classe thread.
- Riga di codice 15: ottenere il nome del thread 2 utilizzando il metodo getName () della classe thread.
Quando esegui il codice sopra, ottieni il seguente output:
Produzione:
I nomi dei thread vengono emessi qui come
- Guru1
- Guru2
Esempio 2:
In questo esempio, impareremo come sovrascrivere i metodi run () e start () di un'interfaccia eseguibile e creeremo due thread di quella classe e li eseguiremo di conseguenza.
Inoltre, stiamo prendendo due lezioni,
- Uno che implementerà l'interfaccia eseguibile e
- Un altro che avrà il metodo principale e verrà eseguito di conseguenza.
demotest pacchetto;public class GuruThread2 {public static void main (String [] args) {// TODO Stub del metodo generato automaticamenteGuruThread3 threadguru1 = nuovo GuruThread3 ("guru1");threadguru1.start ();GuruThread3 threadguru2 = nuovo GuruThread3 ("guru2");threadguru2.start ();}}class GuruThread3 implementa Runnable {Thread guruthread;private String guruname;GuruThread3 (nome stringa) {guruname = nome;}@Oltrepassarepublic void run () {System.out.println ("Thread in esecuzione" + guruname);for (int i = 0; i <4; i ++) {System.out.println (i);System.out.println (guruname);provare {Thread.sleep (1000);} catch (InterructedException e) {System.out.println ("Il thread è stato interrotto");}}}public void start () {System.out.println ("Thread avviato");if (guruthread == null) {guruthread = nuovo thread (questo, guruname);guruthread.start ();}}}
Spiegazione del codice:
- Riga di codice 2: Qui stiamo prendendo una classe "GuruThread2" che avrà il metodo principale in essa.
- Riga di codice 4: qui stiamo prendendo un metodo principale della classe.
- Riga di codice 6-7: Qui stiamo creando un'istanza della classe GuruThread3 (che viene creata nelle righe seguenti del codice) come "threadguru1" e stiamo iniziando il thread.
- Riga di codice 8-9: Qui stiamo creando un'altra istanza della classe GuruThread3 (che viene creata nelle righe seguenti del codice) come "threadguru2" e stiamo iniziando il thread.
- Riga di codice 11: qui stiamo creando una classe "GuruThread3" che implementa l'interfaccia eseguibile (dovrebbe essere implementata da qualsiasi classe le cui istanze devono essere eseguite dal thread).
- Riga di codice 13-14: stiamo prendendo due variabili di classe da cui una è di tipo thread class e l'altra di string class.
- Riga di codice 15-18: stiamo sovrascrivendo il costruttore GuruThread3, che accetta un argomento come tipo di stringa (che è il nome del thread) che viene assegnato alla variabile di classe guruname e quindi il nome del thread viene memorizzato.
- Riga codice 20: qui sovrascriviamo il metodo run () dell'interfaccia eseguibile.
- Riga di codice 21: stiamo emettendo il nome del thread usando l'istruzione println.
- Riga di codice 22-31: qui stiamo usando un ciclo for con contatore inizializzato a 0, e non dovrebbe essere inferiore a 4 (possiamo prendere qualsiasi numero, quindi qui il ciclo verrà eseguito 4 volte) e incrementando il contatore. Stiamo stampando il nome del thread e facendo in modo che il thread dorma per 1000 millisecondi all'interno di un blocco try-catch poiché il metodo sleep ha sollevato un'eccezione controllata.
- Riga codice 33: qui stiamo sovrascrivendo il metodo di avvio dell'interfaccia eseguibile.
- Riga codice 35: Stiamo emettendo il testo "Discussione iniziata".
- Riga di codice 36-40: qui stiamo prendendo una condizione if per verificare se la variabile di classe guruthread ha un valore o no. Se è nullo, stiamo creando un'istanza utilizzando la classe thread che prende il nome come parametro (valore per il quale è stato assegnato nel costruttore). Dopo di che il thread viene avviato utilizzando il metodo start ().
Quando esegui il codice sopra, ottieni il seguente output:
Uscita :
Ci sono due thread quindi, otteniamo due volte il messaggio "Thread avviato".
Otteniamo i nomi del thread come li abbiamo emessi.
Entra nel ciclo for in cui stampiamo il contatore e il nome del thread e il contatore inizia con 0.
Il ciclo viene eseguito tre volte e nel frattempo il thread viene sospeso per 1000 millisecondi.
Quindi, prima otteniamo guru1 poi guru2 e poi di nuovo guru2 perché il thread dorme qui per 1000 millisecondi e poi guru1 e di nuovo guru1, il thread dorme per 1000 millisecondi, quindi otteniamo guru2 e poi guru1.
Riepilogo :
In questo tutorial, abbiamo visto applicazioni multithread in Java e come utilizzare thread singoli e multipli.
- Nel multithreading, gli utenti non vengono bloccati poiché i thread sono indipendenti e possono eseguire più operazioni contemporaneamente
- Le varie fasi del ciclo di vita del filo sono,
- Nuovo
- Runnable
- In esecuzione
- In attesa
- Morto
- Abbiamo anche appreso della sincronizzazione tra i thread, che aiuta l'applicazione a funzionare senza problemi.
- Il multithreading semplifica molte più attività dell'applicazione.