"Xin chào, Amigo! Chúng tôi có thuốc chữa bách bệnh—thuốc chữa mọi bệnh tật. Như chúng ta đã thấy, chuyển mạch không kiểm soát được là một vấn đề."

"Tại sao các chủ đề không thể tự quyết định khi nào chuyển sang chủ đề tiếp theo? Làm mọi thứ họ cần làm và sau đó ra hiệu, «Tôi xong rồi!»?"

"Việc cho phép các luồng tự điều khiển chuyển đổi sẽ là một vấn đề thậm chí còn lớn hơn. Giả sử bạn có một số mã được viết kém và luồng không bao giờ đầu hàng CPU. Ngày trước, đây là cách nó hoạt động. Và đó là một cơn ác mộng."

"Được. Vậy giải pháp là gì?"

" Chặn các chủ đề khác.  Đây là cách nó hoạt động."

Rõ ràng là các luồng can thiệp lẫn nhau khi chúng cố gắng sử dụng các đối tượng và/hoặc tài nguyên được chia sẻ . Như chúng ta đã thấy trong ví dụ với đầu ra của bàn điều khiển: có một bàn điều khiển và tất cả các luồng xuất ra bàn điều khiển đó. Thật lộn xộn.

Vì vậy, một đối tượng đặc biệt đã được phát minh: mutex . Nó giống như một tấm biển trên cửa phòng tắm ghi «có sẵn / có người sử dụng» . Nó có hai trạng thái: đối tượng có sẵn hoặc bị chiếm đóng . Các trạng thái này còn được gọi là «đã khóa» và «đã mở khóa».

Khi một luồng cần một đối tượng được chia sẻ với các luồng khác, nó sẽ kiểm tra mutex được liên kết với đối tượng. Nếu mutex được mở khóa, thì luồng sẽ khóa nó (đánh dấu nó là «đã sử dụng») và bắt đầu sử dụng tài nguyên được chia sẻ. Sau khi luồng đã hoàn thành công việc của mình, mutex được mở khóa (được đánh dấu là «có sẵn»).

Nếu luồng muốn sử dụng đối tượng và mutex bị khóa, thì luồng sẽ ngủ trong khi chờ đợi. Khi mutex cuối cùng được mở khóa bởi luồng chiếm giữ, luồng của chúng tôi sẽ ngay lập tức khóa nó và bắt đầu chạy. Sự tương tự với một dấu hiệu cửa phòng tắm là hoàn hảo.

"Vậy làm cách nào để tôi làm việc với một mutex? Tôi có cần tạo các đối tượng đặc biệt không?"

"Nó đơn giản hơn thế nhiều. Những người tạo ra Java đã tích hợp mutex này vào lớp Object. Vì vậy, bạn thậm chí không cần phải tạo nó. Nó là một phần của mọi đối tượng. Đây là cách nó hoạt động:"

Mã số Sự miêu tả
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
Phương thức hoán đổi hoán đổi các giá trị của biến name1 và name2.

Đ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
name2 = s1; //Ally

String s2 = name1; //Lena
name1 = name2; //Ally
name2 = s2; //Lena
String s1 = name1;
name1 = name2;
//other thread is running
name2 = s1;
//the thread waits until the mutex is unlocked

String s2 = name1;
name1 = name2;
//other thread is running
//other thread is running
name2 = s2;
Điểm mấu chốt
Giá trị của các biến được hoán đổi hai lần, trở về vị trí ban đầu.

Hãy chú ý đến từ khóa  được đồng bộ hóa .

"Ừ, nghĩa là sao?"

"Khi một luồng nhập một khối mã được đánh dấu là đã đồng bộ hóa, máy Java sẽ ngay lập tức khóa mutex của đối tượng được chỉ định trong ngoặc đơn sau từ được đồng bộ hóa. Không luồng nào khác có thể nhập khối này cho đến khi luồng của chúng tôi rời khỏi nó. Ngay sau khi luồng của chúng tôi rời đi khối được đánh dấu là đã đồng bộ hóa, mutex được mở khóa ngay lập tức và tự động và sẽ có sẵn để được mua bởi một luồng khác."

Nếu mutex bị chiếm dụng, thì luồng của chúng ta sẽ đứng yên và đợi nó giải phóng.

"Thật đơn giản và thật tao nhã. Đó là một giải pháp tuyệt vời."

"Vâng. Nhưng bạn nghĩ điều gì sẽ xảy ra trong trường hợp này?"

Mã số Sự miêu tả
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}

public void swap2()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
Các phương thức hoán đổi và hoán đổi2 chia sẻ cùng một mutex ( đối tượng này ).

Điều gì xảy ra nếu một luồng gọi phương thức hoán đổi và một luồng khác gọi phương thức hoán đổi 2?

"Vì mutex giống nhau, luồng thứ hai sẽ phải đợi cho đến khi luồng thứ nhất rời khỏi khối được đồng bộ hóa. Vì vậy, sẽ không có vấn đề gì với việc truy cập đồng thời."

"Làm tốt lắm, Amigo! Đó là câu trả lời chính xác!"

Bây giờ tôi muốn chỉ ra rằng đồng bộ hóa có thể được sử dụng để đánh dấu không chỉ các khối mã mà còn cả các phương thức. Đây là những gì có nghĩa là:

Mã số Điều gì thực sự xảy ra
class MyClass
{
private static String name1 = "Ally";
private static String name2 = "Lena";

public synchronized void swap()
{
String s = name1;
name1 = name2;
name2 = s;
}

public static synchronized void swap2()
{
String s = name1;
name1 = name2;
name2 = s;
}
}
class MyClass
{
private static String name1 = "Ally";
private static String name2 = "Lena";

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}

public static void swap2()
{
synchronized (MyClass.class)
{
String s = name1;
name1 = name2;
name2 = s;
}
}