"สวัสดี Amigo! เรามียาครอบจักรวาล—รักษาทุกโรค ดังที่เราได้เห็นแล้วว่าการสลับด้ายที่ไม่สามารถควบคุมได้เป็นปัญหา"

"เหตุใดเธรดจึงไม่สามารถตัดสินใจได้เองว่าจะเปลี่ยนไปใช้เธรดถัดไปเมื่อใด ทำทุกอย่างที่จำเป็นแล้วส่งสัญญาณว่า «ฉันเสร็จแล้ว!»"

"การอนุญาตให้เธรดควบคุมการสลับจะเป็นปัญหาที่ใหญ่กว่า สมมติว่าคุณมีโค้ดที่เขียนได้ไม่ดี และเธรดไม่เคยยอมจำนนต่อ CPU ย้อนกลับไปในสมัยก่อน นี่คือวิธีการทำงาน และมันก็ค่อนข้างเป็นฝันร้าย"

"ตกลง แล้วอะไรคือทางออก?"

" บล็อกเธรดอื่น  นี่คือวิธีการทำงาน"

เป็นที่ชัดเจนว่าเธรดรบกวนซึ่งกันและกันเมื่อพยายามใช้วัตถุและ/หรือทรัพยากรที่ใช้ร่วมกัน ดังที่เราเห็นในตัวอย่างที่มีเอาต์พุตคอนโซล: มีคอนโซลเดียวและเอาต์พุตเธรดทั้งหมดไปยังคอนโซลนั้น มันยุ่งเหยิง

ดังนั้นจึงมีการคิดค้นวัตถุพิเศษ: mutex มันเหมือนกับป้ายที่ประตูห้องน้ำว่า«ว่าง / ว่าง» มีสองสถานะ: วัตถุพร้อมใช้งานหรือถูกครอบครอง สถานะเหล่านี้เรียกอีกอย่างว่า «ล็อค» และ «ปลดล็อค»

เมื่อเธรดต้องการออบเจ็กต์ที่แชร์กับเธรดอื่น เธรดจะตรวจสอบ mutex ที่เชื่อมโยงกับออบเจ็กต์ หาก mutex ถูกปลดล็อก เธรดจะล็อก (ทำเครื่องหมายเป็น «ถูกครอบครอง») และเริ่มใช้ทรัพยากรที่ใช้ร่วมกัน หลังจากที่เธรดดำเนินการเสร็จสิ้นแล้ว mutex จะถูกปลดล็อก (ทำเครื่องหมายเป็น «ว่าง»)

หากเธรดต้องการใช้วัตถุและ mutex ถูกล็อก เธรดจะเข้าสู่โหมดสลีปในขณะที่รอ ในที่สุดเมื่อ mutex ถูกปลดล็อกโดยเธรดที่ครอบครอง เธรดของเราจะล็อกทันทีและเริ่มทำงาน การเปรียบเทียบกับป้ายประตูห้องน้ำนั้นสมบูรณ์แบบ

"แล้วฉันจะทำงานกับ mutex ได้อย่างไร ฉันจำเป็นต้องสร้างวัตถุพิเศษหรือไม่"

"มันง่ายกว่านั้นมากผู้สร้างของ Java สร้าง mutex นี้ไว้ในคลาส Object คุณจึงไม่ต้องสร้างมันด้วยซ้ำ มันเป็นส่วนหนึ่งของทุกออบเจกต์นี่คือวิธีการทำงานทั้งหมด:"

รหัส คำอธิบาย
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
วิธีการสลับจะสลับค่าของตัวแปร name1 และ name2

จะเกิดอะไรขึ้นหากมีการเรียกจากสองเธรดในเวลาเดียวกัน

การดำเนินการโค้ดจริง รหัสของเธรดแรก รหัสของเธรดที่สอง
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;
บรรทัดล่างสุด
ค่าของตัวแปรถูกสับเปลี่ยนสองครั้ง กลับสู่ตำแหน่งเดิม

ให้ความสนใจกับคำหลัก  ที่ซิงโครไนซ์

“ใช่ หมายความว่าไง”

"เมื่อเธรดเข้าสู่บล็อกของโค้ดที่ระบุว่าซิงโครไนซ์แล้ว เครื่อง Java จะล็อก mutex ของอ็อบเจ็กต์ที่ระบุในวงเล็บทันทีหลังจากคำว่าซิงโครไนซ์ ไม่มีเธรดอื่นสามารถเข้าสู่บล็อกนี้ได้จนกว่าเธรดของเราจะออกจากบล็อก ทันทีที่เธรดของเราออกจากบล็อก บล็อกที่ทำเครื่องหมายว่าซิงโครไนซ์แล้ว mutex จะถูกปลดล็อคโดยอัตโนมัติทันที และเธรดอื่นจะพร้อมใช้งาน"

หาก mutex ถูกครอบครองเธรดของเราจะหยุดนิ่งและรอให้ว่าง

"เรียบง่ายและสง่างามมาก นั่นเป็นวิธีแก้ปัญหาที่สวยงาม"

"ใช่ แต่คุณคิดว่าอะไรจะเกิดขึ้นในกรณีนี้"

รหัส คำอธิบาย
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;
}
}
}
วิธีการ swap และ swap2 ใช้ mutexเดียวกัน( วัตถุ นี้ )

จะเกิดอะไรขึ้นหากเธรดหนึ่งเรียกใช้เมธอด swap และเธรดอื่นเรียกเมธอด swap2

"เนื่องจาก mutex เหมือนกัน เธรดที่สองจึงต้องรอจนกว่าเธรดแรกจะออกจากบล็อกที่ซิงโครไนซ์ ดังนั้นจะไม่มีปัญหาใดๆ กับการเข้าถึงพร้อมกัน"

"ทำได้ดีมาก Amigo! นั่นคือคำตอบที่ถูกต้อง!"

ตอนนี้ฉันต้องการชี้ให้เห็นว่าการซิงโครไนซ์สามารถใช้เพื่อทำเครื่องหมายไม่เพียง แต่บล็อกของโค้ด แต่ยังรวมถึงเมธอดด้วย นี่คือความหมาย:

รหัส เกิดอะไรขึ้นจริงๆ
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;
}
}