"Ciao, Amigo! Ieri abbiamo discusso dei vantaggi e delle comodità del multithreading. Ora è il momento di esaminare gli svantaggi. E, sfortunatamente, non sono piccoli."

In precedenza, abbiamo considerato un programma come un insieme di oggetti che richiamano i metodi l'uno dell'altro. Ora tutto diventa un po' più complicato. Un programma è più simile a un insieme di oggetti che ha diversi "piccoli robot" (thread) che strisciano attraverso di esso ed eseguono i comandi contenuti nei metodi.

Questa nuova interpretazione non annulla la prima. Sono ancora oggetti e chiamano ancora i metodi l'uno dell'altro. Ma dobbiamo ricordare che ci sono diversi thread e ogni thread svolge il proprio lavoro o compito.

Un programma sta diventando più complicato. Thread diversi modificano lo stato di oggetti diversi in base alle attività che eseguono. E possono pestarsi i piedi a vicenda.

Ma le cose peggiori accadono nel profondo della macchina Java. Come ho già detto, l'apparente simultaneità dei thread è ottenuta dal fatto che il processore passa costantemente da un thread all'altro. Passa a un thread, funziona per 10 millisecondi, passa al thread successivo, funziona per 10 millisecondi e così via. E qui sta il problema: questi cambi possono avvenire nei momenti più inopportuni. Considera questo esempio:

Codice del primo thread Codice del secondo thread
System.out.print ("Nick is");
System.out.print ("");
System.out.print ("15");
System.out.print ("");
System.out.print ("years old");
System.out.println ();
System.out.print ("Lena is");
System.out.print ("");
System.out.print ("21");
System.out.print ("");
System.out.print ("years old");
System.out.println ();
Cosa ci aspettavamo di essere visualizzato
Nick ha 15 anni
Lena ha 21 anni
Esecuzione effettiva del codice Codice del primo thread Codice del secondo thread
System.out.print ("Nick is");
System.out.print ("Lena is");
System.out.print (" ");
System.out.print (" ");
System.out.print ("15");
System.out.print ("21");
System.out.print (" ");
System.out.print (" ");
System.out.print ("years old");
System.out.println ();
System.out.print ("years old");
System.out.println ();
System.out.print ("Nick is");
//other thread is running
//other thread is running
System.out.print (" ");
System.out.print ("15");
//other thread is running
//other thread is running
System.out.print (" ");
System.out.print ("years old");
System.out.println ();
//other thread is running
//other thread is running
//other thread is running
System.out.print ("Lena is");
System.out.print (" ");
//other thread is running
//other thread is running
System.out.print ("21");
System.out.print (" ");
//other thread is running
//other thread is running
//other thread is running
System.out.print ("years old");
System.out.println ();
Cosa viene effettivamente visualizzato
Nick è  Lena   ha 15  21  anni

Ed ecco un altro esempio:

Codice Descrizione
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";
public void swap()
{
String s = name1;
name1 = name2;
name2 = s;
}
}
Il metodo scambia swapi valori delle variabili name1e name2.

Cosa potrebbe accadere se viene chiamato da due thread contemporaneamente?

Esecuzione effettiva del codice Codice del primo thread Codice del secondo thread
String s1 = name1; //Ally
name1 = name2; //Lena
String s2 = name1; //Lena(!)
name1 = name2; //Lena
name2 = s1; //Ally
name2 = s2; //Lena
String s1 = name1;
name1 = name2;
//other thread is running
//other thread is running
name2 = s1;
//other thread is running
//other thread is running
//other thread is running
String s2 = name1;
name1 = name2;
//other thread is running
name2 = s2;
La linea di fondo
Entrambe le variabili hanno il valore «Lena».
L'oggetto «Alleato» non ce l'ha fatta. È perso.

"Chi avrebbe mai immaginato che errori come questo fossero possibili con un'operazione di assegnazione così semplice?!"

"Sì, questo problema ha una soluzione. Ma ne parleremo un po' più tardi: ho la gola secca."