"Olá, amigo! Ontem discutimos os benefícios e as conveniências do multithreading. Agora é hora de ver as desvantagens. E, infelizmente, elas não são pequenas."

Anteriormente, víamos um programa como um conjunto de objetos que chamam os métodos uns dos outros. Agora tudo fica um pouco mais complicado. Um programa é mais como um conjunto de objetos que tem vários "pequenos robôs" (threads) rastejando por ele e executando os comandos contidos nos métodos.

Esta nova interpretação não cancela a primeira. Eles ainda são objetos e ainda chamam os métodos uns dos outros. Mas temos que lembrar que existem vários threads e cada thread faz seu próprio trabalho ou tarefa.

Um programa está se tornando mais complicado. Diferentes threads alteram o estado de diferentes objetos com base nas tarefas que executam. E eles podem pisar no pé um do outro.

Mas o pior acontece no fundo da máquina Java. Como já disse, a aparente simultaneidade dos threads é obtida pelo fato de o processador alternar constantemente de um thread para outro. Ele alterna para um thread, funciona por 10 milissegundos, alterna para o próximo thread, funciona por 10 milissegundos e assim por diante. E aqui está o problema: essas trocas podem ocorrer nos momentos mais inoportunos. Considere este exemplo:

Código da primeira thread Código da segunda 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 ();
O que esperávamos que fosse exibido
Nick tem 15 anos
Lena tem 21 anos
Execução real do código Código da primeira thread Código da segunda 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 ();
O que realmente é exibido
Nick é  Lena tem   15  anos 21  anos

E aqui está outro exemplo:

Código Descrição
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";
public void swap()
{
String s = name1;
name1 = name2;
name2 = s;
}
}
O método de troca swapos valores das variáveis name1​​e name2.

O que pode acontecer se for chamado de dois threads ao mesmo tempo?

Execução real do código Código da primeira thread Código da segunda 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;
A linha de fundo
Ambas as variáveis ​​têm o valor «Lena».
O objeto «Ally» não sobreviveu. Está perdido.

"Quem poderia imaginar que erros como esse são possíveis com uma operação de atribuição tão simples?!"

"Sim, esse problema tem solução. Mas falaremos sobre isso um pouco mais tarde - minha garganta está seca."