เนื้อหาหลักของบทความนี้เป็นจุดความรู้ทั่วไปในการสัมภาษณ์ Java: คำหลักที่ผันผวน บทความนี้แนะนำทุกด้านของคำหลักที่ผันผวนในรายละเอียด ฉันหวังว่าหลังจากอ่านบทความนี้คุณสามารถแก้ปัญหาที่เกี่ยวข้องของคำหลักที่ผันผวนได้อย่างสมบูรณ์แบบ
ในการสัมภาษณ์งานที่เกี่ยวข้องกับ Java ผู้สัมภาษณ์หลายคนชอบตรวจสอบความเข้าใจของผู้สัมภาษณ์เกี่ยวกับการพร้อมกันของ Java การใช้คำหลักที่ผันผวนเป็นจุดเริ่มต้นเล็ก ๆ คุณสามารถถามโมเดลหน่วยความจำ Java (JMM) และคุณสมบัติบางอย่างของการเขียนโปรแกรม Java พร้อมกัน ในเชิงลึกคุณยังสามารถตรวจสอบความรู้ที่เกี่ยวข้องกับการใช้งาน JVM และระบบปฏิบัติการที่เกี่ยวข้อง มาใช้กระบวนการสัมภาษณ์สมมุติฐานเพื่อทำความเข้าใจในเชิงลึกเกี่ยวกับคำหลัก Volitile!
เท่าที่ฉันเข้าใจตัวแปรที่ใช้ร่วมกันแก้ไขโดยความผันผวนมีสองลักษณะดังต่อไปนี้:
1. ตรวจสอบให้แน่ใจว่าการมองเห็นหน่วยความจำของเธรดที่แตกต่างกันไปยังการทำงานของตัวแปร
2. คำสั่งห้ามสั่งซื้อใหม่
นี่เป็นเรื่องที่ต้องพูดถึงมากดังนั้นฉันจะเริ่มต้นด้วยโมเดลหน่วยความจำ Java ข้อมูลจำเพาะของเครื่องเสมือน Java พยายามที่จะกำหนดโมเดลหน่วยความจำ Java (JMM) เพื่อป้องกันความแตกต่างของการเข้าถึงหน่วยความจำระหว่างฮาร์ดแวร์และระบบปฏิบัติการต่างๆเพื่อให้โปรแกรม Java สามารถบรรลุเอฟเฟกต์การเข้าถึงหน่วยความจำที่สอดคล้องกันบนแพลตฟอร์มต่างๆ พูดง่ายๆเนื่องจาก CPU ดำเนินการคำแนะนำอย่างรวดเร็วความเร็วการเข้าถึงหน่วยความจำจะช้าลงมากและความแตกต่างไม่ใช่ลำดับความสำคัญคนตัวใหญ่ที่ทำงานกับโปรเซสเซอร์ได้เพิ่มแคชหลายชั้นลงใน CPU ในโมเดลหน่วยความจำ Java การเพิ่มประสิทธิภาพข้างต้นจะถูกแยกออกอีกครั้ง JMM กำหนดว่าตัวแปรทั้งหมดอยู่ในหน่วยความจำหลักคล้ายกับหน่วยความจำทั่วไปที่กล่าวถึงข้างต้นและแต่ละเธรดมีหน่วยความจำการทำงานของตัวเอง มันถือได้ว่าเป็นการลงทะเบียนหรือแคชบน CPU เพื่อความเข้าใจที่ง่าย ดังนั้นการทำงานของเธรดจึงขึ้นอยู่กับหน่วยความจำที่ใช้งานได้ พวกเขาสามารถเข้าถึงหน่วยความจำการทำงานของตนเองเท่านั้นและพวกเขาจะต้องซิงโครไนซ์ค่ากลับไปที่หน่วยความจำหลักก่อนและหลังเลิกงาน ฉันไม่รู้ด้วยซ้ำว่าฉันพูดอะไรเอากระดาษมาวาด:
เมื่อดำเนินการเธรดค่าของตัวแปรจะถูกอ่านก่อนจากหน่วยความจำหลักจากนั้นโหลดไปยังสำเนาในหน่วยความจำที่ใช้งานแล้วส่งผ่านไปยังโปรเซสเซอร์เพื่อดำเนินการ หลังจากการดำเนินการเสร็จสิ้นการคัดลอกในหน่วยความจำการทำงานจะถูกกำหนดค่าจากนั้นค่าในหน่วยความจำการทำงานจะถูกส่งกลับไปยังหน่วยความจำหลักและค่าในหน่วยความจำหลักจะได้รับการอัปเดต แม้ว่าการใช้หน่วยความจำการทำงานและหน่วยความจำหลักนั้นเร็วกว่า แต่ก็นำปัญหาบางอย่าง ตัวอย่างเช่นดูตัวอย่างต่อไปนี้:
i = i + 1;
สมมติว่าค่าเริ่มต้นของฉันคือ 0 เมื่อมีเพียงหนึ่งเธรดที่ดำเนินการผลลัพธ์จะได้รับ 1 แน่นอนเมื่อสองเธรดดำเนินการผลลัพธ์จะได้รับ 2 หรือไม่? นี่ไม่จำเป็นต้องเป็นกรณี นี่อาจเป็นกรณี:
เธรด 1: โหลดฉันจากหน่วยความจำหลัก // i = 0 i + 1 // i = 1 เธรด 2: โหลดฉันจากหน่วยความจำหลัก // เพราะเธรด 1 ไม่ได้เขียนค่าของฉันกลับไปที่หน่วยความจำหลักฉันยังคงเป็น 0 i + 1 // i = 1 เธรด 1: บันทึกฉันเป็นหน่วยความจำหลัก 2: บันทึกฉันเป็นหน่วยความจำหลัก
หากสองเธรดปฏิบัติตามกระบวนการดำเนินการข้างต้นค่าสุดท้ายของฉันคือ 1 จริง ๆ ถ้าการเขียนกลับสุดท้ายช้าและคุณสามารถอ่านค่าของฉันอีกครั้งอาจเป็น 0 ซึ่งเป็นปัญหาความไม่สอดคล้องกันของแคช ต่อไปนี้คือการพูดถึงคำถามที่คุณเพิ่งถาม JMM ส่วนใหญ่เป็นที่ยอมรับเกี่ยวกับวิธีการจัดการกับสามลักษณะของอะตอม, การมองเห็นและการสั่งซื้อในกระบวนการพร้อมกัน ด้วยการแก้ปัญหาทั้งสามนี้ปัญหาของความไม่สอดคล้องกันของแคชสามารถแก้ไขได้ และความผันผวนเกี่ยวข้องกับการมองเห็นและความเป็นระเบียบ
1. Atomicity: ใน Java การดำเนินการอ่านและการกำหนดประเภทข้อมูลพื้นฐานคือการดำเนินการอะตอม การดำเนินการอะตอมที่เรียกว่าหมายความว่าการดำเนินการเหล่านี้ไม่สามารถหยุดยั้งได้และจะต้องเสร็จสิ้นในช่วงระยะเวลาหนึ่งหรือจะไม่ถูกดำเนินการ ตัวอย่างเช่น:
i = 2; j = i; i ++; i = i+1;
ในบรรดาสี่การดำเนินการข้างต้น I = 2 เป็นการดำเนินการอ่านซึ่งจะต้องเป็นการดำเนินการอะตอม j = ฉันคิดว่ามันเป็นการดำเนินการอะตอม ในความเป็นจริงมันแบ่งออกเป็นสองขั้นตอน หนึ่งคือการอ่านค่าของฉันแล้วกำหนดค่าให้ J นี่คือการดำเนินการ 2 ขั้นตอน มันไม่สามารถเรียกได้ว่าเป็นการผ่าตัดอะตอม i ++ และ i = i+ 1 นั้นเทียบเท่ากัน อ่านค่าของฉันเพิ่ม 1 และเขียนกลับไปที่หน่วยความจำหลัก นั่นคือการดำเนินการ 3 ขั้นตอน ดังนั้นในตัวอย่างข้างต้นค่าสุดท้ายอาจมีหลายสถานการณ์เพราะมันไม่สามารถตอบสนองต่ออะตอม ด้วยวิธีนี้มีเพียงการอ่านง่ายๆ การมอบหมายคือการดำเนินการอะตอมหรือการกำหนดเชิงตัวเลขเท่านั้น หากคุณใช้ตัวแปรมีการดำเนินการเพิ่มเติมเพื่ออ่านค่าตัวแปร ข้อยกเว้นคือข้อกำหนดของเครื่องเสมือนช่วยให้สามารถประมวลผลประเภทข้อมูล 64 บิต (ยาวและสองเท่า) ในการดำเนินการ 2 การดำเนินการ แต่การใช้งาน JDK ล่าสุดยังคงใช้การดำเนินการอะตอม JMM ใช้เฉพาะอะตอมพื้นฐาน การดำเนินการเช่น I ++ ด้านบนจะต้องซิงโครไนซ์และล็อคเพื่อให้แน่ใจว่าอะตอมของรหัสทั้งหมด ก่อนที่เธรดจะปล่อยล็อคมันจะแปรงค่าของฉันกลับไปที่หน่วยความจำหลักอย่างหลีกเลี่ยงไม่ได้ 2. การมองเห็น: การพูดถึงการมองเห็น Java ใช้ความผันผวนเพื่อให้ทัศนวิสัย เมื่อตัวแปรถูกแก้ไขโดยความผันผวนการดัดแปลงจะถูกรีเฟรชไปยังหน่วยความจำหลักทันที เมื่อเธรดอื่นจำเป็นต้องอ่านตัวแปรค่าใหม่จะถูกอ่านในหน่วยความจำ สิ่งนี้ไม่ได้รับประกันโดยตัวแปรทั่วไป ในความเป็นจริงการซิงโครไนซ์และล็อคยังสามารถตรวจสอบการมองเห็นได้ ก่อนที่เธรดจะปล่อยล็อคมันจะล้างค่าตัวแปรที่ใช้ร่วมกันทั้งหมดกลับไปที่หน่วยความจำหลัก แต่ซิงโครไนซ์และล็อคมีราคาแพงกว่า 3. การสั่งซื้อ JMM ช่วยให้คอมไพเลอร์และโปรเซสเซอร์สามารถจัดลำดับคำแนะนำใหม่ได้ แต่กำหนดความหมายของ as-if-serial นั่นคือไม่ว่าการจัดเรียงใหม่จะไม่สามารถเปลี่ยนแปลงผลการดำเนินการของโปรแกรมได้ ตัวอย่างเช่นกลุ่มโปรแกรมต่อไปนี้:
double pi = 3.14; // adouble r = 1; // bdouble s = pi * r * r; // c
คำสั่งข้างต้นสามารถดำเนินการใน a-> b-> c โดยผลลัพธ์คือ 3.14 แต่ก็สามารถดำเนินการตามลำดับของ b-> a-> c เนื่องจาก A และ B เป็นสองข้อความอิสระในขณะที่ C ขึ้นอยู่กับ A และ B, A และ B สามารถจัดลำดับใหม่ได้ แต่ C ไม่สามารถจัดอันดับได้ก่อนใน A และ B JMM ทำให้มั่นใจได้ว่าการจัดลำดับใหม่จะไม่ส่งผลกระทบต่อการดำเนินการของเธรดเดียว แต่ปัญหามีแนวโน้มที่จะเกิดขึ้นในหลายเธรด ตัวอย่างเช่นรหัสเช่นนี้:
int a = 0; bool flag = false; โมฆะสาธารณะเขียน () {a = 2; // 1 ธง = true; // 2} โมฆะสาธารณะคูณ () {ถ้า (ธง) {// 3 int ret = a * a; // 4}}หากสองเธรดดำเนินการส่วนโค้ดด้านบนเธรด 1 ก่อนการเขียนการเขียนก่อนแล้วเธรด 2 จากนั้นเรียกใช้ทวีคูณค่า RET จะต้องเป็น 4 หรือไม่ ผลลัพธ์ไม่จำเป็นต้อง:
ดังที่แสดงในรูปที่ 1 และ 2 ในวิธีการเขียนจะถูกจัดลำดับใหม่ เธรด 1 แรกกำหนดค่าสถานะให้เป็นจริงจากนั้นเรียกใช้งานกับเธรด 2, RET คำนวณผลลัพธ์โดยตรงจากนั้นไปที่เธรด 1 ในเวลานี้ A ถูกกำหนดให้ 2 ซึ่งเห็นได้ชัดว่าเป็นขั้นตอนหนึ่งในภายหลัง ในเวลานี้คุณสามารถเพิ่มคำหลักที่ผันผวนลงในธงห้ามการจัดลำดับใหม่ซึ่งสามารถรับรองความเป็นระเบียบของโปรแกรมและคุณยังสามารถใช้เฮฟวี่เวทที่ซิงโครไนซ์และล็อคเพื่อให้แน่ใจว่าเป็นระเบียบ พวกเขาสามารถมั่นใจได้ว่ารหัสในพื้นที่นั้นจะถูกดำเนินการในครั้งเดียว นอกจากนี้ JMM มีคำสั่งโดยธรรมชาตินั่นคือความเป็นระเบียบที่สามารถรับประกันได้โดยไม่ต้องมีวิธีการใด ๆ ซึ่งมักจะเรียกว่าหลักการที่เกิดขึ้นก่อน << JSR-133: โมเดลหน่วยความจำ Java และข้อกำหนดเธรด >> กำหนดกฎต่อไปนี้ก่อนหน้านี้: 1. กฎลำดับโปรแกรม: สำหรับการดำเนินการแต่ละครั้งในเธรดการเกิดขึ้นก่อนที่จะใช้สำหรับการดำเนินการที่ตามมาในเธรด 2. โดเมนระเหย 4. การขนส่ง: หากเกิดขึ้นก่อนที่ B และ B จะเกิดขึ้นก่อน C แล้วเกิดขึ้นก่อน C 5.START () กฎ: ถ้าเธรด A จะทำการดำเนินการด้าย B_START () (เริ่มต้นด้าย B) ดังนั้น ThreadB_Start () จะเกิดขึ้น-การดำเนินการของด้าย ของเธรดการส่งคืนจาก threadb.join () สำเร็จในเธรด A. 7. การขัดจังหวะ () หลักการ: การเรียกไปยังเมธอดอินเตอร์รัปต์ () เกิดขึ้นก่อนเมื่อตรวจพบเหตุการณ์อินเตอร์รัปต์โดยรหัสเธรดที่ถูกขัดจังหวะ คุณสามารถใช้เมธอด Thread.interrupted () เพื่อตรวจสอบว่ามีการหยุดชะงักหรือไม่ 8. สรุป () หลักการ: การเริ่มต้นเสร็จสิ้นของวัตถุเกิดขึ้นก่อนเมื่อวิธีการสุดท้าย () เริ่มต้นขึ้น กฎข้อแรกของกฎลำดับโปรแกรมบอกว่าในเธรดการดำเนินการทั้งหมดจะอยู่ในลำดับ แต่ใน JMM ตราบใดที่ผลการดำเนินการยังคงเหมือนเดิม จุดสนใจของการเกิดขึ้นก่อนที่นี่คือความถูกต้องของผลการดำเนินการเธรดเดี่ยว แต่ไม่สามารถรับประกันได้ว่าสิ่งเดียวกันนี้เป็นจริงสำหรับมัลติเธรด กฎข้อ 2 กฎการตรวจสอบนั้นง่ายต่อการเข้าใจ ก่อนที่จะเพิ่มล็อคคุณสามารถเพิ่มล็อคต่อไปได้เท่านั้น กฎข้อ 3 ใช้กับความผันผวนที่เป็นปัญหา หากเธรดหนึ่งเขียนตัวแปรก่อนและเธรดอื่นจะอ่านได้การดำเนินการเขียนจะต้องเป็นก่อนการดำเนินการอ่าน กฎข้อที่สี่คือการเปลี่ยนแปลงของการเกิดขึ้นก่อน ฉันจะไม่เข้าไปดูรายละเอียดเกี่ยวกับไม่กี่คนต่อไปนี้
จากนั้นเราจำเป็นต้องใช้กฎตัวแปรผันผวนที่กล่าวถึงใหม่: เขียนโดเมนผันผวนเกิดขึ้นก่อนที่จะอ่านโดเมนผันผวนนี้ในภายหลัง ให้ฉันนำเรื่องนี้ออกมาอีกครั้ง ในความเป็นจริงหากตัวแปรถูกประกาศว่าผันผวนแล้วเมื่อฉันอ่านตัวแปรฉันสามารถอ่านค่าล่าสุดได้เสมอ ที่นี่ค่าล่าสุดหมายความว่าไม่ว่าเธรดอื่นใดที่เขียนตัวแปรจะได้รับการอัปเดตเป็นหน่วยความจำหลักทันที ฉันยังสามารถอ่านค่าที่เขียนใหม่จากหน่วยความจำหลัก กล่าวอีกนัยหนึ่งคำหลักที่ผันผวนสามารถรับรองการมองเห็นและความเป็นระเบียบ ลองใช้รหัสด้านบนเป็นตัวอย่าง:
int a = 0; bool flag = false; โมฆะสาธารณะเขียน () {a = 2; // 1 ธง = true; // 2} โมฆะสาธารณะคูณ () {ถ้า (ธง) {// 3 int ret = a * a; // 4}}รหัสนี้ไม่เพียง แต่มีปัญหาโดยการจัดลำดับใหม่แม้ว่า 1 และ 2 จะไม่ได้จัดลำดับใหม่ 3 จะไม่ถูกดำเนินการอย่างราบรื่นเช่นกัน สมมติว่าเธรด 1 ดำเนินการเขียนการเขียนก่อนและเธรด 2 จากนั้นทำการดำเนินการคูณ เนื่องจากเธรด 1 กำหนดธงให้ 1 ในหน่วยความจำที่ใช้งานได้จึงอาจไม่ถูกเขียนกลับไปยังหน่วยความจำหลักทันที ดังนั้นเมื่อเธรด 2 ดำเนินการทวีคูณอ่านค่าธงจากหน่วยความจำหลักซึ่งอาจยังคงเป็นเท็จดังนั้นคำสั่งในวงเล็บจะไม่ถูกดำเนินการ หากเปลี่ยนเป็นสิ่งต่อไปนี้:
int a = 0; ธงบูลผันผวน = false; โมฆะสาธารณะเขียน () {a = 2; // 1 ธง = true; // 2} โมฆะสาธารณะคูณ () {ถ้า (ธง) {// 3 int ret = a * a; // 4}}จากนั้นเธรด 1 จะดำเนินการเขียนก่อนและเธรด 2 จากนั้นเรียกใช้ทวีคูณ ตามหลักการที่เกิดขึ้นก่อนกระบวนการนี้จะเป็นไปตามกฎสามประเภทต่อไปนี้: กฎการสั่งซื้อโปรแกรม: 1 เกิดขึ้นก่อน 2; 3 เกิดขึ้นก่อน 4; (คำสั่งที่มีความผันผวน จำกัด การสั่งซื้อใหม่ดังนั้น 1 จะถูกดำเนินการก่อน 2) กฎระเหย: 2 เกิดขึ้นก่อน 3 กฎสกรรมกริยา: 1 เกิดขึ้นก่อน 4 เมื่อเขียนตัวแปรผันผวน JMM จะล้างตัวแปรที่ใช้ร่วมกันในหน่วยความจำท้องถิ่นที่สอดคล้องกับเธรดกับหน่วยความจำหลัก เมื่ออ่านตัวแปรผันผวน JMM จะตั้งค่าหน่วยความจำในท้องถิ่นที่สอดคล้องกับเธรดเพื่อทำให้เป็นโมฆะและเธรดจะอ่านตัวแปรที่ใช้ร่วมกันจากหน่วยความจำหลักถัดไป
ก่อนอื่นคำตอบของฉันคือไม่สามารถรับประกันอะตอมได้ หากมีการรับประกันว่ามันเป็นเพียงอะตอมสำหรับการอ่าน/การเขียนของตัวแปรระเหยง่ายเดียว แต่ไม่มีอะไรเกี่ยวข้องกับการดำเนินการแบบผสมเช่น Volatile ++ เช่นตัวอย่างต่อไปนี้:
การทดสอบระดับสาธารณะ {สาธารณะผันผวน int inc = 0; โมฆะสาธารณะเพิ่ม () {inc ++; } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {ทดสอบการทดสอบขั้นสุดท้าย = การทดสอบใหม่ (); สำหรับ (int i = 0; i <10; i ++) {เธรดใหม่ () {โมฆะสาธารณะเรียกใช้ () {สำหรับ (int j = 0; j <1000; j ++) test.increase (); - }.เริ่ม(); } ในขณะที่ (thread.activeCount ()> 1) // ตรวจสอบให้แน่ใจว่าเธรดก่อนหน้านี้เสร็จสิ้น thread.yield (); System.out.println (test.inc); -การพูดอย่างมีเหตุผลผลลัพธ์คือ 10,000 แต่มีแนวโน้มว่าจะมีค่าน้อยกว่า 10,000 เมื่อทำงาน บางคนอาจบอกว่าความผันผวนไม่รับประกันการมองเห็น หนึ่งเธรดควรเห็นการปรับเปลี่ยนเป็น Inc โดย Inc และเธรดอื่น ๆ ควรเห็นทันที! แต่การดำเนินการ Inc ++ ที่นี่คือการดำเนินการคอมโพสิตรวมถึงการอ่านค่าของ Inc เพิ่มขึ้นด้วยตัวเองแล้วเขียนกลับไปที่หน่วยความจำหลัก สมมติว่าเธรด A อ่านค่าของ Inc เป็น 10 และถูกบล็อกในเวลานี้เนื่องจากตัวแปรไม่ได้รับการแก้ไขและไม่สามารถเรียกใช้กฎระเหยได้ เธรด B ยังอ่านค่าของ Inc ในเวลานี้ ค่าของ Inc ในหน่วยความจำหลักยังคงอยู่ที่ 10 และจะเพิ่มขึ้นโดยอัตโนมัติและจากนั้นจะถูกเขียนกลับไปยังหน่วยความจำหลักซึ่งคือ 11 ในเวลานี้มันเป็นเธรด A ของการดำเนินการ เนื่องจาก 10 ถูกบันทึกไว้ในหน่วยความจำที่ใช้งานได้จึงยังคงเพิ่มขึ้นและเขียนกลับไปที่หน่วยความจำหลัก 11 เขียนอีกครั้ง ดังนั้นแม้ว่าสองเธรดจะดำเนินการเพิ่มขึ้น () สองครั้ง แต่ก็เพิ่มเพียงครั้งเดียว บางคนพูดว่าไม่ระเหยไม่ได้ทำให้สายแคชเป็นโมฆะ? อย่างไรก็ตามก่อนที่เธรดจะอ่านเธรด B และดำเนินการค่า INC จะไม่ถูกแก้ไขดังนั้นเมื่อเธรด B อ่านมันยังคงอ่าน 10 บางคนก็บอกว่าถ้าเธรด B เขียน 11 กลับไปที่หน่วยความจำหลักจะไม่ตั้งค่าแคชของเธรด อย่างไรก็ตามเธรด A ได้ดำเนินการอ่านแล้ว เฉพาะเมื่อการดำเนินการอ่านเสร็จสิ้นและสายแคชไม่ถูกต้องจะอ่านค่าหน่วยความจำหลัก ดังนั้นเธรด A สามารถดำเนินการต่อไปได้ โดยสรุปในการทำงานแบบคอมโพสิตประเภทนี้ฟังก์ชั่นอะตอมไม่สามารถรักษาได้ อย่างไรก็ตามในตัวอย่างข้างต้นของการตั้งค่าค่าธงเนื่องจากการดำเนินการอ่าน/เขียนของธงเป็นขั้นตอนเดียวมันยังสามารถมั่นใจได้ว่าเป็นอะตอม เพื่อให้แน่ใจว่าอะตอมเราสามารถใช้คลาสการทำงานแบบซิงโครไนซ์ล็อคและอะตอมภายใต้แพ็คเก็ตพร้อมกันนั่นคือการเพิ่มขึ้นของตนเอง (เพิ่ม 1 การดำเนินการ) การลดลงของตนเอง (ลดการดำเนินการ 1 ครั้ง) การดำเนินการเพิ่มเติม (เพิ่มจำนวน)
หากคุณสร้างรหัสแอสเซมบลีด้วยคำหลักที่ผันผวนและรหัสโดยไม่มีคำหลักที่ผันผวนคุณจะพบว่ารหัสที่มีคำหลักที่ผันผวนจะมีคำสั่งคำนำหน้าล็อคเพิ่มเติม คำสั่งคำนำหน้าล็อคนั้นเทียบเท่ากับสิ่งกีดขวางหน่วยความจำ สิ่งกีดขวางหน่วยความจำให้ฟังก์ชั่นต่อไปนี้: 1. เมื่อการจัดลำดับใหม่คำแนะนำต่อไปนี้ไม่สามารถจัดเรียงใหม่ไปยังตำแหน่งก่อนที่จะมีสิ่งกีดขวางหน่วยความจำ 2 ทำแคชของซีพียูนี้เขียนลงในหน่วยความจำ ** ** 3 การกระทำการเขียนจะทำให้เกิดซีพียูอื่น ๆ หรือเคอร์เนลอื่น ๆ
1. เครื่องหมายปริมาณสถานะเช่นเดียวกับธงด้านบนฉันจะพูดถึงอีกครั้ง:
int a = 0; ธงบูลผันผวน = false; โมฆะสาธารณะเขียน () {a = 2; // 1 ธง = true; // 2} โมฆะสาธารณะคูณ () {ถ้า (ธง) {// 3 int ret = a * a; // 4}}การอ่านและการเขียนนี้การดำเนินการกับตัวแปรนี้มีความผันผวนสามารถมั่นใจได้ว่าการแก้ไขจะปรากฏขึ้นทันทีในเธรด เมื่อเปรียบเทียบกับการซิงโครไนซ์ล็อคมีการปรับปรุงประสิทธิภาพที่แน่นอน 2. การใช้งานโหมดซิงเกิลตันโดยทั่วไปตรวจสอบล็อค (DCL) โดยทั่วไป (DCL)
Class Singleton {อินสแตนซ์ Singleton แบบคงที่แบบคงที่ส่วนตัว = NULL; Private Singleton () {} Public Static Singleton GetInstance () {ถ้า (อินสแตนซ์ == null) {ซิงโครไนซ์ (singleton.class) {ถ้า (อินสแตนซ์ == null) อินสแตนซ์ = new Singleton (); }} ส่งคืนอินสแตนซ์; -นี่คือรูปแบบ Singleton ที่ขี้เกียจวัตถุจะถูกสร้างขึ้นเฉพาะเมื่อใช้และเพื่อหลีกเลี่ยงการจัดลำดับคำแนะนำใหม่สำหรับการดำเนินการเริ่มต้นความผันผวนจะถูกเพิ่มเข้าไปในอินสแตนซ์
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้เกี่ยวกับการอธิบายคำหลักที่ผันผวนที่ผู้สัมภาษณ์ Java ชอบที่จะถามในรายละเอียด ฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน เพื่อนที่สนใจสามารถอ้างถึงหัวข้ออื่น ๆ ที่เกี่ยวข้องในเว็บไซต์นี้ต่อไป หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!