# I Thread e concorrenza

Lezione [Concurrency](https://docs.oracle.com/javase/tutorial/essential/concurrency/index.html)  (The Java Tutorials > Essential Classes) per vedere le due modalità di creazione dei thread.

Nel modello classico di programmazione, c'è un'unica *central processor unit* che legge le istruzioni da memoria e le esegue una dopo l'altra. Lo scopo di un programma è di provvedere una sequenza di istruzioni al processore per essere eseguito. Questo è l'unica tipo di programmazione che abbiamo considerato finora.&#x20;

Tuttavia, questo modello di programmazione ha delle limitazioni. I moderni computer hanno molti processori, che permettono loro di compiere più task (lavori) contemporaneamente. Per utilizzare tutte la potenzialità di tutti questi processori, abbiamo bisogno di scrivere programmi che possono fare **esecuzioni parallele** (**parallel processing**). Per i programmatori java, questo significa imparare i **thread**. Un singolo thread è simile a un programma che finora abbiamo scritto, ma più di un thread possono essere eseguiti al medesimo momento, in "parallelo". Questo rende le cose più interessanti ma anche più difficili che la programmazione *single thread* (quella fatta finora) è che i thread in un programma sono raramente completamente indipendenti uno dall'altro. Essi in genere devono coordinarsi e comunicare tra loro.

### Creazione ed esecuzione dei thread

In Java, è rappresentato da un oggetto appartenente alla classe `java.lang.Thread` (o una sottoclasse di questa classe). Lo scopo di un oggetto di tipo **Thread** è di eseguire un singolo metodo e una sola volta. Questo metodo rappresenta il compito che deve essere eseguito dal thread. Il metodo è eseguito dal proprio *flusso di esecuzione* (*thread of control*), che può essere eseguito in parallelo con gli altri thread. Quando l'esecuzione del metodo del thread è terminato o perché il metodo è finito normalmente o a causa di un'eccezione non catturata, il thread finisce di essere attivo. Quando questo succede, non c'è modo per restartare il thread o di utilizzare lo stasso oggetto di tipo `Thread` per far partire un altro thread.

Ci sono due modi per programmare un thread. Uno è di creare una sottoclasse di Thread e definire il metodo `public void run()` nella sottoclasse. Questo metodo `run()` definisce il compito che verrà eseguito dal thread. Cioè, quando il thread è fatto partire, è il metodo `run()` che verrà eseguito nel thread. Per esempio, qui c'è una semplice, ma piuttosto inutile, classe che definisce un thread che non fa altro che stampare un messaggio in standard output:

```java
public class NamedThread extends Thread {
    private String name; // The name of this thread.
    
    public NamedThread(String name) { // Constructor gives name to thread.
        this.name = name;
    }
    
    public void run() { // The run method prints a message to standard output.
        System.out.println("Greetings from thread ’" + name + "’!");
    }
}
```

Per utilizzare `NamedThread`, bisogna chiaramente creare un oggetto appartenente a questa classe. Per esempio,

`NamedThread greetings = new NamedThread("Fred");`

Tuttavia, la semplice creazione dell'oggetto non manda in automatico l'esecuzione del thread o causa l'esecuzione del metodo `run()`. Per fare questo, è necessario invocare il metodo start() dell'oggetto di tipo thread.

In questo esempio, viene fatto con lo statement:

`greetings.start();`

Lo scopo del metodo `start()` è creare un nuovo flusso di esecuzione che eseguirà il metodo `run()` dell'oggetto di tipo `Thread`. Questo nuovo thread verrà eseguito in parallelo con il thread nel quale il metodo `start()` è stato chiamato, insieme con gli altri thread che già esistevano. Il metodo `start()` ritorna immediatamente avendo attivato il nuovo thread, **senza aspettare che il thread abbia terminato**. Questo significa che il codice nel metodo run() del thread è eseguito in parallelo del codice che segue la chiamata al metodo start(). Consideriamo il seguente codice:

```java
NamedThread greetings = new NamedThread("Fred");
greetings.start();
System.out.println("Thread has been started");
```

Dopo che `greetings.start()` è eseguito, ci sono due thread. Uno che scriverà "*Thread has been started*" mentre l'altro vuole scrivere "*Greetings from thread 'Fred'!*". E' importante notare che *questi messaggi possono essere stampati in entrambi gli ordini*. I due thread sono eseguiti simultaneamente e sono in competizione per l'accesso allo standard output, in modo da poter scrivere i propri messaggi. A quale dei due processi capita di essere il primo ad accedere, sarà il primo a scrivere il messaggio. In un normale programma single-thread, le cose accadono in modo definito, prevedibile dall'inizio alla fine. In un programma multi-thread, c'è fondamentalmente indeterminatezza. Noi non sappiamo con certezza in che ordine accadranno le cose. Questa indeterminatezza e quello che rende la programmazione parallela cosi difficile!

Da notare che chiamare `greetings.start()` è molto diverso da chiamare `greetings.run()`. Chiamare `greetings.run()` eseguirà il metodo `run()` nello stesso thread, piuttosto che creare un nuovo thread. Questo significa che tutto il lavoro del metodo `run()` verrà fatto prima che il computer si muova sugli statement che seguono la chiamata a `greetings.run()`. Non c'è parallelismo nè indeterminatezza.

![](/files/Ra0n1uJ3xT5FowCv8UEK)

Questa discussione assume che il computer su cui si stanno eseguendo i programmi abbia più di una CPU, in modo che si possibile che sia il thread originario che il nuovo thread creato siano effettivamente eseguiti in parallelo. Tuttavia, è possibile creare molti thread anche su computer che hanno solo un processore (e, più in generale, è possibile creare molti più thread di quanti siano i processori su un computer). In questo caso, i due thread competeranno nell'utilizzo dell'unica CPU. Tuttavia, c'è ancora indeterminatezza, in quanto il processore può cambiare dall'esecuzione di uno all'altro in modo imprevedibile. In effetti, dal punto di vista del programmatore, non c'è differenza se si programma su un computer mono-processore o multi-processore, e quindi fondamentalmente ignoreremo questa distinzione d'ora in avanti.

&#x20;                                                            \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

Abbiamo detto che ci sono due modi per programmare un thread. Il primo modo è definire una sottoclasse di `Thread`. Il secondo è definire una classe che implementi l'interfaccia `java.lang.Runnable`. L'interfaccia `Runnable` definisce un singolo metodo, `public void run()`. Dato un `Runnable`, è possibile creare un `Thread` il cui compito è eseguire il metodo `run()` di `Runnable`.

La classe `Thread` ha un costruttore che prende un `Runnable` come parametro. Quando un oggetto che implementa l'interfaccia `Runnable` è passato al costruttore, il metodo `run()` del thread semplicemente invocherà il metodo `run()` del `Runnable`, e l'invocazione del metodo `start()` del thread, creerà un nuovo flusso di esecuzione (thread) in cui il metodo `run()` del `Runnable` è eseguito.

Per esempio, in alternativa alla classe `NamedThead`, protremmo definire la classe:

```java
public class NamedRunnable implements Runnable {
  private String name; // The name of this Runnable.

  public NamedRunnable(String name) { // Constructor gives name to object.
    this.name = name;
  }
  
  public void run() { // The run method prints a message to standard output.
    System.out.println("Greetings from runnable ’" + name +"’!");
  }
}
```

Per utilizzare questa versione della classe, possiamo creare un oggetto di tipo `NamedRunnable` e utilizzare questo oggetto per creare un oggetto di tipo `Thread`:

```java
NamedRunnable greetings = new NamedRunnable("Fred");
Thread greetingsThread = new Thread(greetings);
greetingsThread.start();
```

Il vantaggio di fare in questo modo è che ogni oggetto può implementare l'interfaccia `Runnable` che deve contenere il metodo `run()`, che verrà poi eseguito in un thread separato. Questo metodo `run()` ha accesso a ogni cosa nella classe, incluse le variabili e metodi `private`.

&#x20;                                                        \*\*\*\*\*\*\*\*\*\*\*\*

Per aiutare a comprendere come molti thread sono eseguiti in parallelo, consideriamo il semplice programma [javanotes8.ThreadTest1](https://github.com/checksound/EsempioCalcoloNumeriPrimi/blob/main/src/javanotes8/ThreadTest1.java). Questo programma crea diversi thread. Il compito è quello di contare i numeri primi che sono minori di 5000000. (Il particolare task che è eseguito non è importante per il nostro scopo. E' solo un programma demo. Sarebbe insensato avere un programma reale che abbia molti thread che eseguono lo stesso lavoro). I thread che compiono questo task sono definiti nella seguente static nested class:

```java
    /**
     * When a thread belonging to this class is run it will count the
     * number of primes between 2 and 5000000.  It will print the result
     * to standard output, along with its id number and the elapsed
     * time between the start and the end of the computation.
     */
    private static class CountPrimesThread extends Thread {
        int id;  // An id number for this thread; specified in the constructor.
        
        public CountPrimesThread(int id) {
            this.id = id;
        }
        
        public void run() {
            long startTime = System.currentTimeMillis();
            int count = countPrimes(2, 5000000);
            long elapsedTime = System.currentTimeMillis() - startTime;
            System.out.println("Thread " + id + " counted " + 
                    count + " primes in " + (elapsedTime/1000.0) + " seconds.");
        }
    }

```

Il main program chiede quanti thread mandare in esecuzione, e poi crea e fa partire il numero specificati di thread:

```java
    public static void main(String[] args) {
        int numberOfThreads = 0;
        while (numberOfThreads < 1 || numberOfThreads > 25) {
            System.out.print("How many threads do you want to use  (from 1 to 25) ?  ");
            numberOfThreads = TextIO.getlnInt();
            if (numberOfThreads < 1 || numberOfThreads > 25)
                System.out.println("Please enter a number between 1 and 25 !");
        }
        System.out.println("\nCreating " + numberOfThreads + " prime-counting threads...");
        CountPrimesThread[] worker = new CountPrimesThread[numberOfThreads];
        
        for (int i = 0; i < numberOfThreads; i++)
            worker[i] = new CountPrimesThread( i );
        
        for (int i = 0; i < numberOfThreads; i++)
            worker[i].start();
        
        System.out.println("Threads have been created and started.");
    }
```

Quando mando in esecuzione il programma con un solo thread, per l'esecuzione ci impiega circa 2.517 secondi. Quando mando in esecuzione il programma utilizzando otto thread, l'output è:

```
Creating 8 prime-counting threads...
Threads have been created and started.
Thread 0 counted 348513 primes in 8.065 seconds.
Thread 1 counted 348513 primes in 8.081 seconds.
Thread 6 counted 348513 primes in 8.029 seconds.
Thread 4 counted 348513 primes in 8.092 seconds.
Thread 2 counted 348513 primes in 8.145 seconds.
Thread 3 counted 348513 primes in 8.125 seconds.
Thread 5 counted 348513 primes in 8.122 seconds.
Thread 7 counted 348513 primes in 8.094 seconds.
```

Altri esempi creazione thread: [Creazione di thread](https://github.com/checksound/TryThreads#creazione-di-thread)

### Operazioni sui thread

La maggior parte delle API sui thread sono nella classe `Thread` della standard library. Tuttavia, iniziamo con un metodo legato ai thread della classe `Runtime`, una classe che permette ai programmi Java di avere informazioni rispetto all'ambiente in cui sono in esecuzione. Quando facciamo programmazione parallela allo scopo di suddividere il lavoro tra più processori, potrebbe essere utile conoscere quanti processori ha il computer su cui gira l'applicazione. In Java si può conoscere il numero dei processori chiamando la funzione:

`Runtime.getRuntime().availableProcessors()`

che ritorna un `int` con il numero dei processori che sono disponibili alla Java Virtual Machine.

&#x20;                                                       \*\*\*\*\*\*\*\*\*\*\*\*\*\*

Un oggetto di tipo `Thread` ha numerosi metodi per lavorare con i thread. Il più importante è il metodo `start()`, che è stato visto prima.

Una volta che il thread è stato fatto partire (con il metodo `start()`), continuerà finché il metodo `run()` non terminerà per qualche motivo. Alcune volte è utile per un thread saper se un altro thread è terminato. Se `thrd` è un oggetto di tipo `Thread`, allora la funzione `thrd.isAlive()` ritorna un *boolean* che può essere utilizzato per testare se `thrd` è terminato o ancora "vivo" ("alive"). Un thread è vivo tra il momento in cui è fatto partire (tramite l'invocazione del metodo `start()`) e il momento che termina. Dopo che un thread è terminato si dice che è "morto" ("dead"). Ricordiamoci che un thread una volta che è terminato non può essere ristartato (tramite l'invocazione di `start()`).

Il metodo statico `Thread.sleep(milliseconds)` causa al thread che esegue questo metodo di andare in "sleep" ("addormentato") per il numero specificato di millisecondi. Un thread in "sleep" è ancora vivo ma non "running" (non in esecuzione). Mentre un thread è in sleeping, il computer può eseguire ogni altro thread in esecuzione (o programma in esecuzione). `Thread.sleep(milliseconds)` può essere utilizzato per mettere una pausa nell'esecuzione di un thread. Il metodo `sleep()` può lanciare un'eccezione di tipo `InterruptedException`, che è un'eccezione di quelle checked che è obbligatorio che sia gestita. In pratica questo significa che il metodo `sleep()` è invocato all'interno di `try .... catch` per catturare la possibile `InterruptedException`:&#x20;

```java
try {
    Thread.sleep(lengthOfPause);
}
catch (InterruptedException e) {
}
```

Un thread può mandare un **interrupt** a un altro thread per risvegliarlo quando è in sleep o in pausa per certe altre ragioni. Un `Thread`, `thrd`, può essere interrotto chiamando il metodo `thrd.interrupt()`. In questo modo si può  mandare un segnale da un thread a un altro. Un thread sa di essere stato interrotto quando cattura la `InterruptedException`. Fuori da un blocco catch per l'eccezione, un thread può sapere se è stato interrotto chiamando il metodo statico `Thread.interrupted()`. Il metodo dice se il thread corrente - il thread che esegue il metodo - è stato interrotto. Esso ha anche la inusuale proprietà di pulire il flag di interrupted status del thread così che si può controllare solo una volta per l'interruzione. Molto spesso, non dobbiamo fare nulla in risposta a una `InterruptedException` (eccetto la catch).

A volte è necessario che un thread aspetti la fine di un altro thread. Questo è fatto con il metodo `join()` della classe `Thread`. Supponiamo che `thrd` è un `Thread`. Allora, se un thread chiama `thrd.join()`, allora il thread chiamante va in "sleep" finché `thrd` non termina. Se `thrd` è già terminato quando il metodo `thrd.join()` è chiamato, allora semplicemente non ha alcun effetto. Il metodo `join()` può lanciare `InterruptedException`, che deve essere gestita come solitamente. Come esempio, il codice seguente fa partire diversi thread, aspetta che tutti abbiano terminato, e poi stampa il tempo passato per l'esecuzione dei thread:

```java
CountPrimesThread[] worker = new CountPrimesThread[numberOfThreads];
long startTime = System.currentTimeMillis();
for (int i = 0; i < numberOfThreads; i++) {
  worker[i] = new CountPrimesThread();
  worker[i].start();
  }

for (int i = 0; i < numberOfThreads; i++) {
  try {
    worker[i].join(); // Wait until worker[i] finishes, if it hasn’t already.
  }
  catch (InterruptedException e) {
  }
}
// At this point, all the worker threads have terminated.
long elapsedTime = System.currentTimeMillis() - startTime;
System.out.println("Total elapsed time: " + (elapsedTime/1000.0) + " seconds");

  
```

Un lettore attento noterà che questo codice assume che l'eccezione `InterruptedException` non verrà lanciata.

Per essere assolutamente sicuri che il thread worker\[i] abbia terminato in un ambiente dove `InterruptedException` sono possibili, avremmo dovuto fare qualcosa del tipo:

```java
while (worker[i].isAlive()) {
    try {
        worker[i].join();
    }
    catch (InterruptedException e) {
    }
}
```

Un'altra versione del metodo `join()` prende in input un parametro intero che specifica il numero massimo di millisecondi da aspettare. Una chiamata a `thrd.join(m)` aspetterà o fino a che il thread `thrd` abbia terminato o fino a che *m* millisecondi sono passati. Questo metodo può essere utilizzato per permettere a un thread di svegliarsi periodicamente per compiere qualche attività mentre attende. In questo frammento di codice, ad esempio, viene fatto partire un thread, `thrd`, e poi viene stampato un carattere '.' ogni due secondi aspettando finché `thrd` non termina:

```java
System.out.print("Running the thread ");
thrd.start();
while (thrd.isAlive()) {
    try {
        thrd.join(2000);
        System.out.print(".");
    }
    catch (InterruptedException e) {
    }
}
System.out.println(" Done!");
```

### Utilizzo della *sleep* per mandare in pausa il thread

Il metodo statico `sleep(long)` della classe `Thread` permette di mandare in pausa il thread che ha invocato il metodo per un certo numero di millisecondi.

Esempio in `trythreads.simple.SleepMessages`:

```java
package trythreads.simple;

public class SleepMessages {
    public static void main(String args[])
        throws InterruptedException {
        String importantInfo[] = {
            "Mares eat oats",
            "Does eat oats",
            "Little lambs eat ivy",
            "A kid will eat ivy too"
        };
 
        for (int i = 0;
             i < importantInfo.length;
             i++) {
            //Pause for 4 seconds
            Thread.sleep(4000);
            //Print a message
            System.out.println(importantInfo[i]);
        }
    }
}


```

Il metodo `sleep()` può lanciare l'eccezione `java.lang.InterruptedException`, eccezione non di tipo `java.lang.RuntimeException`, quindi da gestire o dichiarare altrimenti nella signature del metodo che invoca `Thread.sleep`. Questa è un'eccezione che `sleep()` lancia quando un altro thread interrompe il thread che ha invocato la `sleep()` ed è in attesa che la `sleep()` termini.

In questo caso essendoci un solo thread l'`InterruptedException` , nessun altro thread può interrompere il thread che invoca la `sleep()` e quindi non è necessario gestirla ma viene dichiarata la `throws` nella signature del `main`.

Vediamo come un thread può interrompere un altro thread.

### Interrupts

Un *interrupt* è un segnale mandato a un thread per indicargli che dovrebbe finire quello che sta facendo e quindi terminare o fare qualcos'altro. E' compito del programmatore decidere cosa fare quando è stato ricevuto un interrupt, ma è moto comune decidere di far terminare il thread.

Un thread invia un *interrupt* invocando il metodo `interrupt()` sull'oggetto di tipo `Thread` del thread che si vuole interrompere.

Once the thread is interrupted its interrupt status is set to true and then based on whether the thread is currently blocked or not following activity takes place:

1. If this thread is blocked in an invocation of the `wait()`, `wait(long)`, or `wait(long, int)` methods of the [Object class](https://knpcode.com/java/java-basics/object-class-java/), or of the `join()`, `join(long)`, `join(long, int)`, `sleep(long)`, or `sleep(long, int)`, methods of this class, then its interrupt status will be cleared (set to false again) and it will receive an **`java.lang.InterruptedException`**.
2. If a thread that is not blocked is interrupted, then the thread’s interrupt status will be set.

**Methods related to thread interruption in Java Thread class**

Apart from the method `interrupt()` already discussed above there are two more methods in `java.lang.Thread` class related to thread interruption `interrupted()` and `isInterrupted()`.

* **void interrupt()**– Interrupts this thread.
* **static boolean interrupted()**– Checks whether the current thread has been interrupted. Also clears the interrupted status of the thread.
* **boolean isInterrupted()**– Tests whether this thread has been interrupted. This method doesn’t change the interrupted status of the thread in any way.

### Join

This method waits until the thread on which it is called terminates. There are three overloaded versions of `join()` method in Java `Thread` class.

* **public final void join() throws InterruptedException**– Waits indefinitely for this thread to die.
* **public final void join(long millis) throws InterruptedException**– Waits at most the time in milliseconds for this thread to die.
* **public final void join(long millis, int nanos) throws InterruptedException**– Waits at most the time in milliseconds plus additional time in nanoseconds for this thread to die

### isAlive

Method, `isAlive()`, tests if this thread is alive. **A thread is alive if it has been started and has not yet died** (`run()` method terminated). Method returns true if thread is alive otherwise it returns false.

**isAlive() method syntax**

```java
public final boolean isAlive()
```

### Esempio utilizzo dei metodi *join()*, *join(millis)*, *sleep(millis)* e *isAlive()*

Ricapitolando l'utilizzo dei metodi con l'esempio `trythreads.simple.SimpleThreads`:

```java
package trythreads.simple;

public class SimpleThreads {

    // Display a message, preceded by
    // the name of the current thread
    static void threadMessage(String message) {
        String threadName =
            Thread.currentThread().getName();
        System.out.format("%s: %s%n",
                          threadName,
                          message);
    }

    private static class MessageLoop
       implements Runnable {
        
        public void run() {
            String importantInfo[] = {
                "Mares eat oats",
                "Does eat oats",
                "Little lambs eat ivy",
                "A kid will eat ivy too"
            };
            
            try {
                for (int i = 0;
                     i < importantInfo.length;
                     i++) {
                    // Pause for 4 seconds
                    Thread.sleep(4000);
                    // Print a message
                    threadMessage(importantInfo[i]);
                }
            } catch (InterruptedException e) {
                threadMessage("I wasn't done!");
            }
        }
    }

    public static void main(String args[])
        throws InterruptedException {

        // Delay, in milliseconds before
        // we interrupt MessageLoop
        // thread (default one hour).
        long  patience = 1000 * 60 * 60;

        // If command line argument
        // present, gives patience
        // in seconds.
        if (args.length > 0) {
            try {
                patience = Long.parseLong(args[0]) * 1000;
            } catch (NumberFormatException e) {
                System.err.println("Argument must be an integer.");
                System.exit(1);
            }
        }

        threadMessage("Starting MessageLoop thread");
        long startTime = System.currentTimeMillis();
        Thread t = new Thread(new MessageLoop());
        t.start();

        threadMessage("Waiting for MessageLoop thread to finish");
        // loop until MessageLoop
        // thread exits
        while (t.isAlive()) {
            threadMessage("Still waiting...");
            // Wait maximum of 1 second
            // for MessageLoop thread
            // to finish.
            t.join(1000);
            if (((System.currentTimeMillis() - startTime) > patience)
                  && t.isAlive()) {
                threadMessage("Tired of waiting!");
                t.interrupt();
                // Shouldn't be long now
                // -- wait indefinitely
                t.join();
            }
        }
        threadMessage("Finally!");
    }
}
```

### Esempi prima parte

[Esempi su utilizzo di `join()`](https://github.com/checksound/TryThreads#utilizzo-del-metodo-threadjoin)

[Su utilizzo di `interrupt()`](https://github.com/checksound/TryThreads#interruzione-dei-thread)

### Pit stop

Esercizi riepilogo prima parte:

* creazione dei thread;
* utilizzo del metodo `Thread.sleep(long timemillis)`;
* utilizzo metodo `join()` di `Thread` per sincronizzarsi sulla fine di un thread;
* utilizzo del metodo `interrupt()` della classe `Thread`;

{% content-ref url="/pages/Q76yt1AM2TfEWZ8aUp5i" %}
[Esercizi multithreading](/corsojava/i-thread-e-concorrenza/esercizi-multithreading.md)
{% endcontent-ref %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://checksound.gitbook.io/corsojava/i-thread-e-concorrenza.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
