Thread in Java

Creazione di un Thread in Java (1)

I thread in Java vengono creati estendendo la classe Thread e definendo il metodo run (il codice che il thread eseguirà).

Per eseguire il nuovo thread è sufficiente invocare il metodo start.

public class CreaThread extends Thread {
    public void run() {
        System.out.println("Saluti dal thread " + this.getName());
    }
    
    public static void main(String args[]) {
        CreaThread t = new CreaThread();
        t.start();
    }
}

Creazione di un Thread in Java (2)

Se c’è esigenza di estendere altre classi, i thread possono anche essere creati come oggetti della classe Thread, al cui costruttore viene passato un oggetto che implementa l’interfaccia Runnable, che richiede l’implementazione del metodo run.

public class CreaThread2 implements Runnable {
    public void run() {
        System.out.println("Saluti dal thread "
                           + Thread.currentThread().getName());
    }

    public static void main(String args[]) {
        CreaThread2 r = new CreaThread2();
        Thread t = new Thread(r);
        t.start();
    }
}

Addormentare un Thread

Come per i thead POSIX, possiamo anche “addormentare” un thread Java, in questo caso il tempo è dato in millisecondi ed è necessario gestire l’eccezione InterruptedException sollevata da sleep nel caso il thread t venga interrotto ad esempio tramite t.interrupt().

public void run()  {
    try {
        sleep(1000); // attende un secondo
    } catch(InterruptedException e) {
        System.out.println("["+getName()+"]"+" mi hanno interrotto!");
        return; 
    } 

Esercizio

Creare n thread, rallentarli tramite sleep(), provare ad interromperne l’attesa utilizzando t.interrupt() e attendere la terminazione con t.join() (analogamente a quanto si fa con i thread POSIX), dove t è l’oggetto thread.

Aggiungere opportune print per osservare l’esecuzione.

(La soluzione è sulle note, guardatela dopo aver provato da soli!)

I Monitor di Java

In Java è implementata una forma semplificata dei monitor con le seguenti caratteristiche:

Sincronizzare porzioni di codice

NOTA: la sincronizzazione è “rientrante”: è possibile chiamare un metodo synchronized da un altro synchronized senza problemi.

Esercizio

Implementare due thread che lavorano su un contatore condiviso, osservare le usuali interferenze e rimediare ponendo il codice all’interno di metodi synchronized o all’interno del costrutto synchronized(this) { ... } .

Suggerimento: mettere il contatore in una classe apposita (che fungerà da monitor) e implementare i metodi per l’incremento e la lettura/stampa del valore.

La soluzione è nelle note, guardatela dopo aver provato da soli.

C’è un terzo esercizio sulle note (produttore e consumatore)!