Il problema
Dovremmo piuttosto parlare al plurale, poter svolgere più operazioni contemporaneamente (a questo serve il multithreading) risulta utile in più spesso di quanto si possa pensare. Ad esempio:
- voglio portare a termine un lavoro più velocemente
- devo fare una elaborazione impegnativa ma non voglio bloccare l'interfaccia grafica
- devo tener d'occhio una situazione mentre faccio altro
Questi casi sono molto diversi tra loro e fanno sorgere problemi diversi: ad esempio se voglio elaborare un calcolo più velocemente potrei voler divedere il problema da risolvere in più parti (cosa non affatto ovvia da fare in tutti i casi) oppure due thread diversi potrebbero andare a modificare contemporaneamente la stessa struttura dati portandola in uno stato inconsistente (diciamo insensato per capirci).
Fortunatamente Java prevede l'uso dei thread fin dalla sua versione iniziale e per questo
ci mette a disposizione diversi oggetti che ci semplificano molto la vita. I due principali che
possiamo usare per creare un nuovo thread sono appunto
java.lang.Thread
e java.lang.Runnable,
il secondo è più flessibile ma... il primo è più facile da usare!
Utilizzare la classe Thread
non è complicato: basta estendere la classe e
implementarne il metodo run()
, questo metodo è quello che verrà chiamato
quando si avvia il thread e che una volta terminato fa passare il thread stesso
nello stato di "died" (sarebbe a dire "terminato").
public class Esecutore extends Thread { @Override public void run(){ // codice da eseguire nel thread } }
Per quanto riguarda il problema dell'accesso concorrente alle strutture dati mensionato sopra la libreria di Java esplicita chiaramente se un oggetto è utilizzabile senza problemi e senza fare ulteriori controlli da due thread diversi: ad esempio l'oggetto java.util.Vector è definito "thread-safe" (e quindi utilizzabile tranquillamente) mentre java.util.ArrayList fa lo stesso lavoro ma non è thread-safe (ragionevolmente dovendo fare meno controlli è più veloce).