Esercizi multithreading

1 - Possibili flussi

Dato il seguente codice:

class EsempioThread extends Thread {

    public void run() {
	System.out.println("THREAD_A");
    	System.out.println("THREAD_B");
    	System.out.println("THREAD_C");
    	System.out.println("THREAD_D");
    	System.out.println("THREAD_E");
    }
	
    public static void main(String[] args) 
        throws InterruptedException {

        EsempioThread t1 = new EsempioThread();
        t1.start();

        // t1.join();

        System.out.println("MAIN_A");
        System.out.println("MAIN_B");
        System.out.println("MAIN_C");
        System.out.println("MAIN_D");
        System.out.println("MAIN_E");

  }
	
}

Quali sono i possibili flussi di esecuzione delle istruzioni?

Esempi di flussi possibili (il simbolo A < B vuol dire che l'istruzione A è eseguita prima di B):

  • MAIN_A < MAIN_B < MAIN_C < MAIN_D < THREAD_A < THREAD_B < THREAD_C < THREAD_D < THREAD_E < MAIN_E

  • MAIN_A < MAIN_B < THREAD_A < MAIN_C < THREAD_B < THREAD_C < MAIN_D < MAIN_E < THREAD_D < THREAD_E

  • THREAD_A < MAIN_A < THREAD_B < MAIN_B <THREAD_C < MAIN_C < THREAD_D < MAIN_D < THREAD_E < MAIN_E

Mentre ad esempio il seguente flusso non è possibile:

  • MAIN_A < THREAD_B < THREAD_A < MAIN_B < MAIN_D < MAIN_C < THREAD_C < THREAD_D < MAIN_E < THREAD_E

Vedi esempio:

Nell'esempio sopra sono state aggiunte delle Thread.sleep() tra le diverse println, solo per aumentare il livello di concorrenza tra i thread e aumentare così la variabilità dell'output di esecuzione.

Esempi di output di due esecuzioni del programma EsempioThreadMain:

Notate che l'output dell'esecuzione non è deterministico.

DOMANDA

Se togliamo il commento all'istruzione t1.join() nel codice del main dell'esempio sopra (riga 31), qual è l'output dell'esecuzione?

Giustificate la vostra risposta.

2 - Creazione di thread contatore

Crea un'applicazione che abbia due contatori che in modo concorrente stampino a video il valore dalle propria variabile counter: uno parte da 0, poi 1, 2.... per 100 passi quindi fino a 99, l'altro contatore parte da 100, poi 101, 103 fino a 199 (sempre 100 passi). Facciamo inoltre che ogni contatore tra un numero e l'altro stampato a video, aspetti qualche centinaio di millisecondi, in modo da vedere meglio a video l'esecuzione contemporanea delle stampe a video dei due contatori e aumenti il livello di multiprogrammazione (suggerimento: utilizzate la sleep della classe Thread).

Qui lo pseudocodice del contatore:

Activity diagram - flusso esecuzione dell'applicazione

3 - Utilizzo di join

Fare un ulteriore versione che stampi un messaggio dal metodo main quando i due thread hanno finito di stampare l'incremento del progressivo. Suggerimento: utilizzate il metodo join della classe Thread per sincronizzarsi con la fine dei due thread.

Activity diagram - flusso esecuzione dell'applicazione

4 - Numero contatori generico

Generalizzare l'applicazione dell'esercizio 2 affinché sia possibile da riga di comando passare il numero di contatori da creare e il main thread aspetti che tutti i contatori abbiano finito attraverso il metodo join() della classe Thread. Dopo che tutti i thread hanno finito scrive a video il messaggio "FINE APPLICAZIONE".

5 - Interruzione di un thread in esecuzione

  1. Scrivere un'applicazione che abbia un thread che in un ciclo infinito scriva a standard output un numero random diverso ad ogni ciclo. Utilizzate la classe standard java.util.Random per generare numeri random:

Se dopo 10 secondi volessimo stopparlo come potremmo fare?

Suggerimento: utilizzate il metodo interrupt() della classe Thread.

2. Creare un'altra applicazione che prende da standard input il comando per stoppare l'applicazione quando lo desiderate.

Last updated