CodeGym /Corsi /JAVA 25 SELF /Parametri e priorità dei thread

Parametri e priorità dei thread

JAVA 25 SELF
Livello 51, Lezione 3
Disponibile

1. Passaggio di parametri ai thread

Quando avviate un thread, spesso volete passargli un certo «lavoro»: il nome di un file, un intervallo di numeri o un saluto. Un thread senza parametri è come un corriere senza indirizzo: corre per la città ma non sa dove consegnare la pizza.

Come si fa?

In Java i thread si creano di solito in due modi:

  • Ereditando dalla classe Thread
  • Implementando l'interfaccia Runnable (o usando un'espressione lambda)

Il passaggio dei parametri si fa più spesso tramite il costruttore della classe che implementa Runnable. È semplice, sicuro e chiaro. Rendete i campi final — e proteggerete i parametri da modifiche provenienti da altri thread. L'uso di setter/campi pubblici è foriero di problemi di sincronizzazione.

Esempio 1: thread con parametro tramite costruttore

Miglioriamo l'app di esempio: elaborazione degli ordini degli utenti in un thread separato.

public class OrderProcessor implements Runnable {
    private final String orderId;

    public OrderProcessor(String orderId) {
        this.orderId = orderId;
    }

    @Override
    public void run() {
        System.out.println("Elaboro l'ordine: " + orderId + " nel thread " + Thread.currentThread().getName());
        // Qui potrebbe esserci un'elaborazione lunga...
    }
}

Creiamo e avviamo i thread:

public class Main {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new OrderProcessor("ORDER-001"));
        Thread thread2 = new Thread(new OrderProcessor("ORDER-002"));
        thread1.start();
        thread2.start();
    }
}

Output atteso:

Elaboro l'ordine: ORDER-001 nel thread Thread-0
Elaboro l'ordine: ORDER-002 nel thread Thread-1

Esempio 2: thread con parametro tramite espressione lambda (Java 8+)

Se il compito è semplice, si può fare a meno di una classe separata.

public class Main {
    public static void main(String[] args) {
        String user1 = "Vasya";
        String user2 = "Katya";

        Thread thread1 = new Thread(() -> {
            System.out.println("Ciao, " + user1 + " da " + Thread.currentThread().getName());
        });

        Thread thread2 = new Thread(() -> {
            System.out.println("Ciao, " + user2 + " da " + Thread.currentThread().getName());
        });

        thread1.start();
        thread2.start();
    }
}

Perché non conviene usare setter/getter per passare parametri?
Se passate i parametri tramite setter o campi pubblici, c'è il rischio che un altro thread ne cambi il valore proprio durante l'esecuzione. Questo può portare a bug difficili da individuare. Meglio rendere i campi final e passarli tramite costruttore.

2. Priorità dei thread

In Java ogni thread ha una priorità — un numero intero da 1 a 10, che dice allo scheduler quanto è «importante» quel thread rispetto agli altri. Per impostazione predefinita tutti i thread hanno priorità 5 (Thread.NORM_PRIORITY).

Importante: la priorità è solo un «suggerimento» per il sistema operativo. Non è una garanzia che un thread con priorità 10 lavorerà più velocemente di uno con priorità 1. Tutto dipende dal sistema operativo, dalle sue impostazioni e dal carico attuale.

Come impostare la priorità di un thread?

La classe Thread ha i metodi:

  • setPriority(int newPriority)
  • getPriority()

E tre costanti standard:

  • Thread.MIN_PRIORITY (1)
  • Thread.NORM_PRIORITY (5)
  • Thread.MAX_PRIORITY (10)

Esempio 3: impostare la priorità di un thread

public class PriorityDemo {
    public static void main(String[] args) {
        Runnable task = () -> {
            System.out.println("Thread " + Thread.currentThread().getName() +
                    " con priorità " + Thread.currentThread().getPriority());
        };

        Thread low = new Thread(task, "LowPriority");
        Thread norm = new Thread(task, "NormalPriority");
        Thread high = new Thread(task, "HighPriority");

        low.setPriority(Thread.MIN_PRIORITY);    // 1
        norm.setPriority(Thread.NORM_PRIORITY);  // 5
        high.setPriority(Thread.MAX_PRIORITY);   // 10

        low.start();
        norm.start();
        high.start();
    }
}

Output atteso (l'ordine delle righe non è garantito!):

Thread LowPriority con priorità 1
Thread HighPriority con priorità 10
Thread NormalPriority con priorità 5

La priorità influisce sull'ordine di esecuzione?

Nella maggior parte dei casi — no. Le priorità possono influire su quanto tempo di CPU viene assegnato a un thread, ma non garantiscono l'ordine di avvio o di completamento. Non basate la logica del programma sulle priorità — usatele come «suggerimenti morbidi», ad esempio per fare in modo che un thread in background non disturbi quello principale.

Tabella: costanti di priorità dei thread

Costante Valore Descrizione
Thread.MIN_PRIORITY
1 Priorità più bassa
Thread.NORM_PRIORITY
5 Priorità normale
Thread.MAX_PRIORITY
10 Priorità più alta

3. Denominazione dei thread

Il nome del thread è un «soprannome» nel mondo del multitasking. Quando avete decine di thread, è più facile fare debug se invece di "Thread-7" nel log vedete "FileUploader-1". È particolarmente importante nell'analisi dei log e nella ricerca degli errori.

Come assegnare un nome a un thread?

Il nome si può indicare direttamente nel costruttore di Thread oppure impostare con il metodo setName. Per conoscere il nome corrente — getName.

Thread t = new Thread(() -> {
    System.out.println("Sto lavorando!");
}, "MyThreadName");
t.start();

Esempio 4: thread con nome

public class NamedThreads {
    public static void main(String[] args) {
        Thread threadA = new Thread(() -> {
            System.out.println("Sono il thread: " + Thread.currentThread().getName());
        }, "Downloader");

        Thread threadB = new Thread(() -> {
            System.out.println("Sono il thread: " + Thread.currentThread().getName());
        });
        threadB.setName("Uploader");

        threadA.start();
        threadB.start();
    }
}

Output atteso:

Sono il thread: Downloader
Sono il thread: Uploader

4. Pratica: più thread con parametri, priorità e nomi diversi

Mettiamo tutto insieme in un unico esempio: ogni ordine — un thread separato con il proprio nome e priorità.

public class OrderProcessor implements Runnable {
    private final String orderId;
    private final int processingTimeMs;

    public OrderProcessor(String orderId, int processingTimeMs) {
        this.orderId = orderId;
        this.processingTimeMs = processingTimeMs;
    }

    @Override
    public void run() {
        System.out.println("[" + Thread.currentThread().getName() + "] Ho iniziato l'elaborazione dell'ordine " + orderId +
                " (priorità " + Thread.currentThread().getPriority() + ")");
        try {
            Thread.sleep(processingTimeMs); // simulazione del lavoro
        } catch (InterruptedException e) {
            System.out.println("[" + Thread.currentThread().getName() + "] Interrotto!");
        }
        System.out.println("[" + Thread.currentThread().getName() + "] Ho terminato l'elaborazione dell'ordine " + orderId);
    }

    public static void main(String[] args) {
        Thread fastOrder = new Thread(new OrderProcessor("FAST-ORDER", 500), "FastOrderThread");
        Thread normalOrder = new Thread(new OrderProcessor("NORMAL-ORDER", 1000), "NormalOrderThread");
        Thread slowOrder = new Thread(new OrderProcessor("SLOW-ORDER", 2000), "SlowOrderThread");

        fastOrder.setPriority(Thread.MAX_PRIORITY);
        normalOrder.setPriority(Thread.NORM_PRIORITY);
        slowOrder.setPriority(Thread.MIN_PRIORITY);

        fastOrder.start();
        normalOrder.start();
        slowOrder.start();
    }
}

Cosa vedremo:

  • Ogni thread stampa quale ordine sta elaborando, il proprio nome e la priorità.
  • Il tempo di elaborazione è simulato con Thread.sleep.
  • L'ordine di completamento dei thread può non coincidere con la priorità.

5. Dettagli importanti e particolarità

Passaggio dei parametri: solo tramite costruttore!

Così è più sicuro. Dichiarate i parametri come final — non potranno essere modificati dopo la creazione dell'oggetto e nessun altro thread potrà «infilare» i propri valori. È fondamentale per prevenire le race condition sui dati.

Priorità: non costruiteci sopra la logica di business

Le priorità sono come chiedere al cameriere: «Posso avere il caffè un po' più in fretta?». A volte funziona, a volte no. È una raccomandazione per il sistema operativo, non una regola di esecuzione.

Nomi dei thread: usateli per il debug

Fa risparmiare moltissimo tempo nell'analisi dei log. Abituatevi a impostare subito nomi significativi.

6. Errori tipici nel lavoro con parametri e priorità dei thread

Errore n. 1: passare parametri tramite campi pubblici. Se dichiarate i parametri come campi ordinari e li cambiate dopo l'avvio del thread, potete ottenere risultati imprevedibili. Usate campi final e il costruttore.

Errore n. 2: aspettarsi che la priorità garantisca l'ordine. Avete impostato Thread.MAX_PRIORITY — e pensate che il thread sarà sempre il primo? No. Non usate le priorità per la sincronizzazione o per governare la logica.

Errore n. 3: thread senza nome nei log. Quando nei log ci sono solo «Thread-3», «Thread-7» — trovare il colpevole è difficile. Date ai thread nomi significativi usando il costruttore o setName.

Errore n. 4: usare lo stesso oggetto Runnable per più thread. Se l'oggetto Runnable conserva stato e lo passate a più thread, questi «condivideranno» i parametri — strada diretta verso le race condition. Create un Runnable separato per ogni thread.

Errore n. 5: passare parametri tramite metodi set*. Se impostate i parametri tramite metodi set* già dopo la creazione/avvio del thread, i valori possono cambiare «al volo» — classica race condition.

1
Compito
JAVA 25 SELF, livello 51, lezione 3
Bloccato
Gestione degli agenti nel marketplace online 🛍️
Gestione degli agenti nel marketplace online 🛍️
1
Compito
JAVA 25 SELF, livello 51, lezione 3
Bloccato
Coordinamento dei robot in una fabbrica intelligente 🏭
Coordinamento dei robot in una fabbrica intelligente 🏭
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION