ฉันเชื่อว่าผู้อ่านที่เข้าใจ Java multi-threading จะรู้ถึงบทบาทของมันอย่างชัดเจน คำสำคัญระเหยใช้ในการประกาศตัวแปรประเภทง่าย ๆ เช่น int, float, boolean และประเภทข้อมูลอื่น ๆ หากประเภทข้อมูลแบบธรรมดาเหล่านี้ถูกประกาศว่ามีความผันผวน การดำเนินการกับข้อมูลเหล่านั้นจะกลายเป็นอะตอมมิก แต่สิ่งนี้มีข้อจำกัดบางประการ ตัวอย่างเช่น n ในตัวอย่างต่อไปนี้ไม่ใช่อะตอมมิก:
คัดลอกรหัสรหัสดังต่อไปนี้:
ตำนานแพ็คเกจ;
JoinThread คลาสสาธารณะขยายเธรด
-
int ระเหยคงที่สาธารณะ n = 0;
การรันโมฆะสาธารณะ ()
-
สำหรับ (int i = 0; i < 10; i++)
พยายาม
-
n = n + 1;
sleep(3); // เพื่อให้ผลการรันสุ่มมากขึ้น ให้ดีเลย์ 3 มิลลิวินาที
-
จับ (ยกเว้น e)
-
-
-
โมฆะคงที่สาธารณะ main (String [] args) พ่นข้อยกเว้น
-
เธรดเธรด[] = เธรดใหม่[100];
สำหรับ (int i = 0; i < threads.length; i++)
// สร้าง 100 เธรด
เธรด [i] = JoinThread ใหม่ ();
สำหรับ (int i = 0; i < threads.length; i++)
//เรียกใช้ 100 เธรดที่เพิ่งสร้างขึ้น
กระทู้[i].เริ่มต้น();
สำหรับ (int i = 0; i < threads.length; i++)
//ดำเนินการต่อหลังจากดำเนินการครบ 100 เธรดแล้ว
กระทู้[i].เข้าร่วม();
System.out.println("n=" + JoinThread.n);
-
-
หากการดำเนินการบน n เป็นอะตอมมิก ผลลัพธ์สุดท้ายควรเป็น n=1000 อย่างไรก็ตาม เมื่อดำเนินการโค้ดพื้นที่ข้างต้น เอาต์พุต n มักจะน้อยกว่า 1000 ซึ่งแสดงว่า n=n+1 ไม่ใช่การดำเนินการระดับอะตอม . เหตุผลก็คือ สำหรับตัวแปรธรรมดาที่ประกาศความผันผวน หากค่าปัจจุบันเกี่ยวข้องกับค่าก่อนหน้าของตัวแปร คำสำคัญระเหยจะไม่มีผลใดๆ ซึ่งหมายความว่านิพจน์ต่อไปนี้ไม่ใช่การดำเนินการแบบอะตอมมิก:
คัดลอกรหัสรหัสดังต่อไปนี้:
n = n + 1;
n++;
หากคุณต้องการทำให้สถานการณ์นี้เป็นการดำเนินการแบบอะตอมมิก คุณต้องใช้คำสำคัญที่ซิงโครไนซ์ โค้ดข้างต้นสามารถเปลี่ยนเป็นรูปแบบต่อไปนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
ตำนานแพ็คเกจ;
JoinThread คลาสสาธารณะขยายเธรด
-
int สาธารณะคงที่ n = 0;
โมฆะซิงโครไนซ์สาธารณะแบบคงที่ inc ()
-
n++;
-
การรันโมฆะสาธารณะ ()
-
สำหรับ (int i = 0; i < 10; i++)
พยายาม
-
inc(); // n = n + 1 เปลี่ยนเป็น inc();
sleep(3); // เพื่อให้ผลการรันสุ่มมากขึ้น ให้ดีเลย์ 3 มิลลิวินาที
-
จับ (ยกเว้น e)
-
-
-
โมฆะคงที่สาธารณะ main (String [] args) พ่นข้อยกเว้น
-
เธรดเธรด[] = เธรดใหม่[100];
สำหรับ (int i = 0; i < threads.length; i++)
// สร้าง 100 เธรด
เธรด [i] = JoinThread ใหม่ ();
สำหรับ (int i = 0; i < threads.length; i++)
//เรียกใช้ 100 เธรดที่เพิ่งสร้างขึ้น
กระทู้[i].เริ่มต้น();
สำหรับ (int i = 0; i < threads.length; i++)
//ดำเนินการต่อหลังจากดำเนินการครบ 100 เธรดแล้ว
กระทู้[i].เข้าร่วม();
System.out.println("n=" + JoinThread.n);
-
-
โค้ดด้านบนเปลี่ยน n=n+1 เป็น inc() โดยที่วิธีการ inc ใช้คำสำคัญที่ซิงโครไนซ์สำหรับการซิงโครไนซ์วิธีการ ดังนั้นควรระมัดระวังเมื่อใช้คีย์เวิร์ด volatile ไม่ได้หมายความว่าตัวแปรชนิดธรรมดาจะถูกแก้ไขด้วยค่า volatile n+1 , n++ ฯลฯ คีย์เวิร์ดระเหยจะไม่ถูกต้อง การดำเนินการกับตัวแปรจะเป็นระดับอะตอมก็ต่อเมื่อค่าของตัวแปรไม่เกี่ยวข้องกับค่าก่อนหน้า ตัวอย่างเช่น n = m + 1 สิ่งนี้ เป็นระดับเดิม ดังนั้นคุณต้องใช้ความระมัดระวังเมื่อใช้คีย์ระเหย หากคุณไม่แน่ใจ คุณสามารถใช้การซิงโครไนซ์แทนการระเหยได้