corsoJava
  • Corso JAVA
  • Introduzione linguaggio
  • Verifica tipi primitivi vs reference
  • Esercizi su equals
  • Introduzione su oggetti
  • Packages e import
  • Polimorfismo
    • Pit stop
  • Enum
  • String è speciale
  • Eccezioni
  • Nested Classes
  • Array, ArrayList e Hash Table
    • Esempio gioco carte
  • Linked data structures
  • Tipi generici
  • Comparing Java and C# Generics - Jonathan Pryor's web log
  • Contenitori
    • Esempi con classi container
  • Input/Output streams, Files
  • Basic I/O
  • Java IO Tutorial
  • Networking
  • I Thread e concorrenza
    • Esercizi multithreading
    • Thread interference
    • Esercizi thread interference
    • wait(), notify() e notifyAll() per la sincronizzazione tra i thread
    • Verifiche produttore/consumatore
    • Lock esplicito - java.util.concurrent.Locks
    • Semafori
    • Programmare con i thread
    • I Virtual Thread
    • Materiale
  • I Thread e networking
  • Esempi Java Socket Programming
  • Esempi Javascript Socket Programming
  • Messaggi datagram e invio multicast
  • Lambda Expression
  • Java Stream
  • Data Oriented Programming in Java
  • Java improved its 'Hello World' experience
  • Appendice A: utilizzo classe Scanner
  • Java For The Experienced Beginner
  • Modern Java
  • CodeJava - Java Core
  • Is OOP Relevant Today?
  • Book
Powered by GitBook
On this page
  1. I Thread e concorrenza

Esercizi thread interference

1) (1 punto) Quale metodo viene invocato su un oggetto di tipo thread per mandare un thread in esecuzione?

2) (1 punto) Qual'è il metodo dell'interfaccia Runnable che deve essere implementato per creare una classe di tipo Runnable?

3) (1 punto) Scrivete il codice di un thread che scrive 5 volte "CIAO", compresa la parte per lanciare il thread in esecuzione.

4) (3 punti) Il metodo interrupt() invocato su una variabile di tipo thread che cosa genera se il thread sta eseguendo la sleep()?

5) (3 punti) All'interno di un thread t1 viene fatto partire un thread t2.

Quale metodo va invocato su t2 per far si che t1 interrompa la sua esecuzione finché t2 non sia terminato?

6) (2 punti) L'accesso a una variabile condivisa da parte di due o più thread si chiama:

- deadlock

- sequenza critica

- InterruptedException

7) (1 punti) Quali sono le due tecniche di base utilizzate da Java per evitare che l'accesso a una variabile condivisa da parte di più thread dia risultati inconsistenti?

8) (2 punti) Abbiamo una variabile di tipo Contatore con un metodo per decrementare il valore, decrement() e un metodo che restituisce il valore getValue();

Qui sotto l'esempio di come si deve comportare un oggetto di tipo Contatore.

Contatore contatore = new Contatore(5);
contatore.decrement();
int valore = contatore.getValue(); // ritorna valore=4
contatore.decrement();
valore = contatore.getValue(); // ritorna valore=3Java

Implementare la classe Contatore scrivendo il codice, in modo che l'accesso da parte di più thread non crei una sequenza critica nel caso due thread eseguano contemporaneamente l'operazione di decrement().

RISPOSTA:

Una semplice classe Contatore che implementa i due metodi come esposti sopra potrebbe essere:

public class Contatore {
    
    private int value;
    
    public Contatore(int value) {
        this.value = value;
    }

    public void decrement() {
        value--;
    }

    public int getValue() {
        return value;
    }

}

Ora per rendere sicura la sezione critica del metodo decrement() o lo rendo synchronized o in modo equivalente creo un blocco synchronized sull'oggetto (con this). Sotto le due versioni equivalenti.

// versione metodi synchronized

public class Contatore {

    private int value;
    
    public Contatore(int value) {
        this.value = value;
    }

    public synchronized void decrement() {
        value--;
    }

    public synchronized int getValue() {
        return value;
    }

}
// versione blocchi synchronized

public class Contatore {

    private int value;
    
    public Contatore(int value) {
        this.value = value;
    }

    public void decrement() {
        synchronized(this) {
            value--;
        }
    }

    public int getValue() {
        synchronized(this) {
            return value;
        }
    }

}

9) (2 punti) Implementare una classe Contatore come quella precedente ma che permetta a due thread t1 e t2 a uno di accedere al metodo increment() e all’altro a quello getValue() contemporaneamente, mentre non possono accedere contemporaneamente a increment() o a getValue().

RISPOSTA:

La soluzione è avere due oggetti distinti su cui ottenere il lock utilizzando i blocchi synchonized:


public class Contatore {
    
    private int value;
    
    private Object obj1 = new Object();
    private Object obj2 = new Object();
    
    public Contatore(int value) {
        this.value = value;
    }

    public void decrement() {
        synchronized(obj1) {
            value--;
        }
    }

    public int getValue() {
        synchronized(obj2) {
            return value;
        }
    }

}

In questo modo un thread può acquisire il lock su obj1 per eseguire il metodo decrement() e contemporaneamente un altro thread può acquisire il lock su obj2 per eseguire il metodo getValue().

Vedi:

10) (4 punti) E’ data la classe Decrementer di tipo Thread che agisce su una variabile di tipo Contatore e decrementa il contatore finché non arriva a 0 e quindi termina l'esecuzione del thread (codice qui sotto).

public class Decrementer extends Thread {

		private Contatore contatore;

		public Decrementer(Contatore contatore) {
			this.contatore = contatore;
		}

		public void run() {
				
				while(true) {
						
						boolean isZero = (0 == contatore.getValue());  // step 1
						if(isZero)  // CONDIZIONE D'USCITA step 2
							return;
						else
							contatore.decrement();  // step 3
				
				}  // fine while
			
		}  // fine run

}

Immaginate due thread t1 e t2 di tipo Decrementer vengono mandati in esecuzione contemporaneamente passandogli una stessa variabile di tipo Contatore.

Domanda 1: Con quale flusso di esecuzione potrebbe succedere che i due thread, t1 e t2, non terminino non arrivando mai alla condizione d'uscita?

Domanda 2: Come si potrebbe cambiare il codice per far si che invece i due thread terminino?

SOLUZIONE

PreviousThread interferenceNextwait(), notify() e notifyAll() per la sincronizzazione tra i thread

Last updated 2 years ago

Anche il metodo getValue() è stato sincronizzato per garantire la relazione di happends-before su variabili condivisa. Vedi: .

Memory Consistency Properties
GitHub - checksound/SimulatoreAccessoContatoreRandomGitHub
GitHub - checksound/EsempioContatoreDecrementerGitHub
Esempio contatore decrement
Logo
Logo