Un thread (di controllo) è una lista di istruzioni eseguite sequenzialmente da un programma. I thread di un programma condividono uno stesso spazio di indirizzamento. Pur avendo stack e variabili locali separate, condividono le variabili globali. I thread sono "leggeri", nel senso che la creazione, distruzione e sincronizzazione sono relativamente economiche grazie alla condivisione dello spazio di indirizzamento. Le ragioni per organizzare un programma in un certo numero di thread possono essere molteplici:
- Certi programmi si scrivono più semplicemente, in special modo le collezioni di compiti debolmente connessi (cioè largamente indipendenti).
- I programmi interattivi risultano più efficienti laddove il servizio dell'input o il display dell'output sono organizzati in thread distinti.
- I programmi sono potenzialmente parallelizzabili su architetture multi-processore o multi-core.
- Il problema in esame richiede parti di programma in comunicazione asincrona tra loro.
- E' utile imporre una struttura modulare al codice.
I/O non bloccante
Una delle motivazioni forti per la programmazione concorrente mediante thread è l'ottenimento di servizi non bloccanti per Input/Output. Quando l'applicazione ha necessità di effettuare un I/O, è opportuno che non si blocchi, in modo da consentire che altre operazioni non dipendenti da quell'I/O possano essere effettuate. Una tecnica di gestione dell'I/O non bloccante, utilizzata ad esempio nei microcontrollori usati nelle board per il physical computing, è il polling, cioè la verifica ciclica dell'accadimento di eventi su un insieme di dispositivi di input. La ciclicità del polling è gestita da un timer. L'I/O non bloccante si può realizzare mediante i thread. La lettura di un certo dispositivo si può assegnare ad un certo thread il quale si blocca in attesa dei dati. Gli altri thread, che non dipendono dalla lettura del dato, possono però procedere in maniera concorrente.
Diagrammi di attivazione
Il codice Processing seguente invoca il metodo stampa() sull'oggetto cl
della classe Classe1.
class Classe1 {
void stampa() {
for (int i=0; i< 100; i++) println("yep");
}
}
void setup() {
Classe1 cl = new Classe1();
cl.stampa();
}
![]() |
Thread, allora è possibile procedere
all'attivazione di un thread secondario mediante invocazione
del metodo start(). Il codice va riscritto come
class Classe2 extends Thread{
void run() {
for (int i=0; i< 100; i++) println("yep");
}
}
void setup() {
Classe2 cl = new Classe2();
cl.start();
}
stampa() ora si chiama
run(). Il metodo start() esiste
nelle superclassi di Classe2 (nella classe
Thread, e si occupa dell'invocazione del metodo
run(). Questa volta il flusso di elaborazione,
riportato in Figura 2 presenta due thread.
![]() |
Nota:
Runnable di
Java. E' questa modalità che bisogna usare se si vuole
attivare un nuovo thread su un oggetto di una classe che è
già dichiarata come estensione di un'altra classe.






