back to top

Java: gestione di più thread contemporaneamente

Se sei interessato a comprendere come la Java Virtual Machine (JVM) gestisca più thread in esecuzione contemporaneamente, questo articolo ti guiderà attraverso un esempio pratico. Modificheremo la classe EsempioThread per vedere il risultato dell’output a schermo relativo alla gestione dei thread.

Esempio di Classi Thread in Java

Iniziamo definendo la classe EsempioThread come illustrato nel seguente codice:

Pubblicità
public class EsempioThread implements Runnable {
  
  private int numeroThread;

  public EsempioThread(int n) {
    setNumeroThread(n);
  }

  public void setNumeroThread(int n) {
    numeroThread = n;
  }

  public int getNumeroThread() {
    return numeroThread;
  }

  public void run() {
    for (int n = 0; n < 6; n++) {
      System.out.println("*** thread numero " + getNumeroThread() + " in esecuzione");
      System.out.println("l'indice n vale: " + n);
      try {
        Thread.sleep(1000);
      } catch (InterruptedException exc) {
        System.out.println("Errore durante il sonno del thread");
      }
    }
  }
}

La variabile di classe numeroThread serve per identificare quale thread è in esecuzione. Il metodo Thread.sleep() sospende il thread per un tempo pari al valore passato come parametro, espresso in millisecondi. Inoltre, gestiamo l’eccezione di tipo InterruptedException utilizzando un blocco try-catch per garantire che il programma continui a funzionare senza interruzioni in caso di errore.

Implementazione di Thread Multipli

Adesso modifichiamo la classe di implementazione per lanciare due thread contemporaneamente:

public class Implementazione {
  
  public static void main(String[] args) {
    EsempioThread r1 = new EsempioThread(1);
    EsempioThread r2 = new EsempioThread(2);
    
    Thread nuovoThread1 = new Thread(r1);
    Thread nuovoThread2 = new Thread(r2);

    nuovoThread1.start();
    nuovoThread2.start();
  }  
}

Passando i valori 1 e 2 al costruttore della classe EsempioThread, possiamo identificare i due thread durante l’esecuzione. L’output del programma, osservato durante alcune iterazioni, sarà simile al seguente:

*** thread numero 1 in esecuzione
l'indice n vale: 0

*** thread numero 2 in esecuzione
l'indice n vale: 0

*** thread numero 1 in esecuzione
l'indice n vale: 1

*** thread numero 2 in esecuzione
l'indice n vale: 1

Dall’output possiamo notare un importante vantaggio della programmazione con i thread: durante il blocco di un thread, l’altro thread può continuare la propria esecuzione. Senza l’uso dei thread, avremmo dovuto attendere che un thread completasse tutte le sue iterazioni prima di procedere con l’altro. Questo approccio sarebbe altamente inefficiente poiché, per gran parte del tempo, l’applicazione rimarrebbe sospesa e la CPU inattiva.

Effetti della Rimozione di Thread.sleep()

Ricapitolando, nei nostri esempi, quando un thread viene sospeso, il controllo viene passato all’altro e viceversa. Ma cosa accade se eliminiamo il metodo sleep? Procediamo a modificare la classe EsempioThread rimuovendo il blocco try-catch e sostituendo il ciclo for con 400 iterazioni. Ecco il nuovo comportamento:

public void run() {
  for (int n = 0; n < 400; n++) {
    System.out.println("*** thread numero " + getNumeroThread() + " in esecuzione");
    System.out.println("l'indice n vale: " + n);
  }
}

Controllando l’output, noterai che il thread 1 inizia a stampare le proprie iterazioni, ma a un certo punto l’output sarà simile al seguente:

*** thread numero 1 in esecuzione
l'indice n vale: 273

*** thread numero 1 in esecuzione
l'indice n vale: 274

*** thread numero 2 in esecuzione
l'indice n vale: 0

Quello che è successo è che la JVM ha automaticamente sospeso il thread 1 per dare spazio al thread 2, il quale inizierà a eseguire le proprie iterazioni. Questo comportamento è noto come scheduling dei thread, ovvero la scelta dinamica di quale thread sospendere e quale attivare. Questo concetto è fondamentale nel multi-tasking dei sistemi operativi moderni e consente l’esecuzione simultanea di più programmi.

Infine, è importante capire che la decisione su quale thread sospendere dipende da numerosi fattori e può variare ad ogni esecuzione dell’applicazione. Pertanto, se rilanciamo il programma, non è garantito che il thread 1 si interrompa sempre all’iterazione 274, ma potrebbe farlo in un altro punto, a causa della presenza di altri processi in esecuzione sulla macchina.

Conclusioni e Prossimi Passi

Con quanto appreso in questa guida, ora hai gli strumenti necessari per creare applicazioni complesse e scalabili in Java. Dopo aver studiato la teoria, ricorda che la pratica è fondamentale: prova, sperimenta, commetti errori e correggili per evolvere come programmatore.

Pubblicità
Articolo precedente
Articolo successivo