Multithreading in Java – Tutto ciò che DEVI sapere

Quando eseguiamo un’applicazione nel mondo reale, utilizziamo buoni processori per una esecuzione più veloce. Tuttavia, solo la velocità del processore non può rendere l’applicazione più veloce. Uno dei modi migliori per creare un’applicazione efficiente in termini di prestazioni è utilizzare il multithreading.

Cosa è il Multithreading?

Il multithreading è un concetto di programmazione in cui l’applicazione può creare una piccola unità di attività da eseguire in parallelo. Se stai lavorando su un computer, esso esegue più applicazioni e alloca potenza di elaborazione per ognuna di esse. Un programma semplice viene eseguito in sequenza e le istruzioni di codice vengono eseguite una alla volta. Questa è un’applicazione single-threaded. Ma se il linguaggio di programmazione supporta la creazione di thread multipli e li passa al sistema operativo per l’esecuzione in parallelo, allora si parla di multithreading.

Multithreading vs Multiprocessing

Quando parliamo di multithreading, non ci interessa se la macchina ha un processore a 2 core o a 16 core. Il nostro compito è creare un’applicazione multithreaded e lasciare che il sistema operativo si occupi dell’allocazione e dell’esecuzione. In breve, il multithreading non ha nulla a che fare con il multiprocessing.

Come Java Supporta il Multithreading?

Java offre un ottimo supporto per le applicazioni multithreading. Java supporta il multithreading attraverso la classe Thread. Il Thread di Java ci consente di creare un processo leggero che esegue alcune attività. Possiamo creare più thread nel nostro programma e avviarli. Il runtime di Java si occupa di creare istruzioni a livello di macchina e di collaborare con il sistema operativo per eseguirle in parallelo.

Quali sono i diversi tipi di thread?

Esistono due tipi di thread in un’applicazione: il thread utente e il thread daemon. Quando avviamo un’applicazione, il main è il primo thread utente creato. Possiamo creare sia thread utente che thread daemon. Quando tutti i thread utente vengono eseguiti, la JVM termina il programma.

Cosa si intende per Priorità del Thread?

Quando creiamo un thread, possiamo assegnargli una priorità. Possiamo impostare priorità diverse per thread diversi, ma ciò non garantisce che un thread con priorità più alta si eseguirà prima di un thread con priorità più bassa. Lo scheduler del thread è parte dell’implementazione del sistema operativo e quando un thread viene avviato, la sua esecuzione è controllata dallo scheduler del thread e la JVM non ha alcun controllo sulla sua esecuzione.

Come creiamo un thread in Java?

Possiamo creare thread implementando l’interfaccia Runnable o estendendo la classe Thread.

Thread t = new Thread(new Runnable(){
    @Override
    public void run() {
    }
});

Quanto sopra è una dichiarazione in una riga per creare un nuovo thread. Qui stiamo creando un Runnable come classe anonima. Se conosci le espressioni lambda, possiamo creare un thread con un codice molto più breve.

Runnable runnable = () -> System.out.println("Hello");

Una volta creato un thread, dobbiamo avviare la sua esecuzione chiamando il metodo start().

runnable.start();

I have written a lot of posts explaining the concepts of multithreading in Java. You can go through these in sequence to learn everything about multithreading, its real-life usage, thread lifecycle, thread pool, etc.

1. Thread e Runnable in Java

Questo è il primo post riguardante la classe Thread e l’interfaccia Runnable. Imparerai anche riguardo al Processo e al Thread. Qual è la differenza tra Thread e Processo? I vantaggi dell’uso dei Thread e come possiamo crearne utilizzando l’interfaccia Runnable e la classe Thread. Questo post confronta anche l’interfaccia Runnable con la classe Thread.

2. Java Thread Sleep

Il metodo Java Thread sleep viene utilizzato per mettere in pausa l’esecuzione del thread corrente. Utilizzeremo Thread sleep ampiamente nei post futuri, quindi è bene sapere come funziona e se è preciso o no.

3. Java Thread Join

A volte abbiamo bisogno di aspettare che altri thread finiscano la loro esecuzione prima di poter procedere. Possiamo ottenere questo utilizzando il metodo di join del Thread, imparare come funziona e quando dovremmo utilizzarlo.

4. Stati del thread Java

Comprendere i diversi stati del thread è importante. Scopri come un thread cambia il suo stato e come il programmatore di thread del sistema operativo modifica lo stato di un thread.

5. Java Thread wait, notify e notifyAll

La classe Object di Java contiene tre metodi per comunicare lo stato di blocco di una risorsa. Impara con l’uso di esempi di questi metodi della classe Object in un’implementazione semplice di Wait-Notify.

6. Sicurezza dei Thread e Sincronizzazione

Sappiamo che i Thread condividono le risorse dell’oggetto, il che può portare a corruzione dei dati perché queste operazioni non sono atomiche. Scopri come possiamo ottenere la sicurezza dei thread in Java utilizzando diversi metodi. Leggi questo post per apprendere l’uso corretto della sincronizzazione, dei metodi sincronizzati e dei blocchi sincronizzati.

7. Eccezione Java nel thread principale

La JVM crea il primo thread utilizzando il metodo principale. Questo post spiega alcune eccezioni comuni che vediamo nella vita quotidiana, qual è la loro causa principale e come risolverle.

8. Sicurezza dei thread nella classe Singleton

In questo articolo, imparerai i concetti di base per creare una classe Singleton. Quali sono i problemi di sicurezza dei thread con diverse implementazioni? Come possiamo ottenere la sicurezza dei thread nella classe Singleton.

9. Thread Daemon in Java

A simple article explaining daemon threads and how we can create daemon threads in java.

10. Thread Local in Java

Sappiamo che i thread condividono le variabili degli oggetti ma cosa succede se vogliamo avere variabili locali al thread create a livello di classe. Java fornisce la classe di utilità ThreadLocal per creare variabili locali al thread. Continua a leggere per scoprire come possiamo creare variabili ThreadLocal nel programma Java.

11. Java Thread Dump

Lo snapshot del thread Java fornisce le informazioni sul thread corrente. Uno snapshot del thread è utile per analizzare i problemi di prestazione dell’applicazione. Puoi utilizzare lo snapshot del thread per individuare e risolvere situazioni di deadlock. Questo post spiega i diversi metodi che possono essere utilizzati per generare snapshot del thread in Java.

12. Come Analizzare il Deadlock in Java

Il deadlock è una situazione in cui più thread sono in attesa l’uno dell’altro per rilasciare risorse causando una dipendenza ciclica. Questo articolo discute la situazione in cui possiamo ottenere un deadlock in un programma Java. Come possiamo utilizzare lo Thread dump per trovare il deadlock e le migliori pratiche per evitare il deadlock in un programma Java.

13. Thread Timer di Java

Questo post spiega come possiamo utilizzare le classi Java Timer e TimerTask per creare lavori da eseguire ad intervalli pianificati, un esempio di programma che ne mostra l’utilizzo e come possiamo annullare il timer.

14. Problema del Produttore-Consumatore di Java

Prima di Java 5, il problema del produttore-consumatore poteva essere risolto utilizzando i metodi wait() e notify(), ma l’introduzione di BlockingQueue lo ha reso molto facile. Scopri come possiamo utilizzare BlockingQueue per risolvere il problema del produttore-consumatore in Java.

15. Java Thread Pool

Il pool di thread di Java è una raccolta di thread worker in attesa di elaborare lavori. L’introduzione di Java 5 del framework Executor ha reso molto semplice creare un pool di thread in Java. Possiamo utilizzare le classi Executors e ThreadPoolExecutor per creare e gestire un pool di thread.

16. Java Callable Future

A volte vogliamo che il nostro thread restituisca alcuni valori che possiamo utilizzare. In tal caso, possiamo utilizzare Java 5 Callable, che è simile all’interfaccia Runnable. Possiamo utilizzare il framework Executor per eseguire compiti Callable.

17. Esempio di Java FutureTask

La classe FutureTask è la classe concreta di base che implementa l’interfaccia Future. Lo usiamo con l’implementazione Callable e Executors per il processing asincrono. La classe FutureTask fornisce metodi di implementazione per controllare lo stato del compito e restituire il valore al programma chiamante una volta che il suo processing è terminato. Risulta utile quando si desidera sovrascrivere alcuni dei metodi di implementazione dell’interfaccia Future.

Conclusione

Il multithreading è un argomento molto ampio e scrivere tutto su di esso in un singolo post non sarebbe stato possibile. Se segui i post precedenti in sequenza, imparerai tutto sul multithreading in Java.

Source:
https://www.digitalocean.com/community/tutorials/multithreading-in-java