"Xin chào, Amigo! Hôm qua chúng ta đã thảo luận về những lợi ích và tiện lợi của đa luồng. Bây giờ là lúc để xem xét những nhược điểm. Và thật không may, chúng không hề nhỏ."

Trước đây, chúng ta xem chương trình như một tập hợp các đối tượng gọi các phương thức của nhau. Bây giờ mọi thứ trở nên phức tạp hơn một chút. Một chương trình giống như một tập hợp các đối tượng có một số "rô bốt nhỏ" (luồng) bò qua nó và thực hiện các lệnh có trong các phương thức.

Cách giải thích mới này không hủy bỏ cách giải thích đầu tiên. Chúng vẫn là các đối tượng và chúng vẫn gọi các phương thức của nhau. Nhưng chúng ta phải nhớ rằng có một số luồng và mỗi luồng thực hiện công việc hoặc nhiệm vụ riêng của mình.

Một chương trình đang trở nên phức tạp hơn. Các luồng khác nhau thay đổi trạng thái của các đối tượng khác nhau dựa trên các tác vụ mà chúng thực hiện. Và họ có thể dẫm lên chân nhau.

Nhưng điều tồi tệ nhất xảy ra sâu bên trong máy Java. Như tôi đã nói, tính đồng thời rõ ràng của các luồng đạt được nhờ thực tế là bộ xử lý liên tục chuyển từ luồng này sang luồng khác. Nó chuyển sang một luồng, hoạt động trong 10 mili giây, chuyển sang luồng tiếp theo, hoạt động trong 10 mili giây, v.v. Và đây là vấn đề: những chuyển đổi này có thể xảy ra vào những thời điểm không thích hợp nhất. Hãy xem xét ví dụ này:

Mã của chủ đề đầu tiên Mã của chủ đề thứ hai
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 ();
Những gì chúng tôi mong đợi sẽ được hiển thị
Nick 15 tuổi
Lena 21 tuổi
Thực thi mã thực tế Mã của chủ đề đầu tiên Mã của chủ đề thứ hai
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 ();
Những gì thực sự được hiển thị
Nick  Lena   15  21  tuổi

Và đây là một ví dụ khác:

Mã số Sự miêu tả
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";
public void swap()
{
String s = name1;
name1 = name2;
name2 = s;
}
}
Phương thức hoán đổi swapcác giá trị của biến name1name2biến.

Điều gì có thể xảy ra nếu nó được gọi từ hai luồng cùng một lúc?

Thực thi mã thực tế Mã của chủ đề đầu tiên Mã của chủ đề thứ hai
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;
Điểm mấu chốt
Cả hai biến đều có giá trị «Lena».
Đối tượng «Ally» đã không làm được. Nó bị mất.

"Ai có thể đoán được rằng những lỗi như thế này lại có thể xảy ra với một thao tác gán đơn giản như vậy?!"

"Vâng, vấn đề này có một giải pháp. Nhưng chúng ta sẽ nói về điều này một chút sau - cổ họng tôi khô khốc."