คำหลักที่ผันผวนของ Java
ในการประมวลผลพร้อมกันของเธรด Java มีความสับสนมากมายในการใช้คำหลักระเหยง่าย ฉันคิดว่าการใช้คำหลักนี้สามารถทำให้ทุกอย่างเป็นไปด้วยดีเมื่อใช้การประมวลผลพร้อมกันหลายเธรด
ภาษา Java รองรับมัลติเธรด เพื่อแก้ปัญหาการเกิดขึ้นพร้อมกันของเธรดบล็อกแบบซิงโครนัสและกลไกคำหลักที่ผันผวนได้รับการแนะนำภายในภาษา
ซิงโครไนซ์
ทุกคนคุ้นเคยกับบล็อกที่ซิงโครไนซ์และพวกเขาจะถูกนำไปใช้ผ่านคำหลักที่ซิงโครไนซ์ ด้วยคำสั่งที่ซิงโครไนซ์และบล็อกมีเพียงเธรดเดียวเท่านั้นที่สามารถใช้งานได้ในเวลาเดียวกันเมื่อเข้าถึงมัลติเธรด
วิธีการแก้ไขหรือบล็อกรหัส
ระเหย
สำหรับตัวแปรที่แก้ไขด้วยความผันผวนเธรดจะอ่านค่าที่แก้ไขมากที่สุดของตัวแปรทุกครั้งที่ใช้ตัวแปร ความผันผวนจะถูกนำไปใช้ในทางที่ผิดและใช้สำหรับการดำเนินการอะตอม
มาดูตัวอย่างด้านล่าง เราใช้เคาน์เตอร์ ทุกครั้งที่เธรดเริ่มต้นเมธอด Inc จะถูกเรียกให้เพิ่มหนึ่งรายการลงในตัวนับ
สภาพแวดล้อมการดำเนินการ - JDK เวอร์ชัน: JDK1.6.0_31, หน่วยความจำ: 3G CPU: x86 2.4G
เคาน์เตอร์ระดับสาธารณะ {จำนวน int คงที่สาธารณะ = 0; Public Static Void Inc () {// ความล่าช้าที่นี่คือ 1 มิลลิวินาทีทำให้ผลลัพธ์เห็นได้ชัดว่าลอง {thread.sleep (1); } catch (interruptedException e) {} นับ ++; } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {// เริ่มต้น 1,000 เธรดในเวลาเดียวกันเพื่อทำการคำนวณ i ++ และดูผลลัพธ์ที่แท้จริงสำหรับ (int i = 0; i <1000; i ++) {เธรดใหม่ } // ค่าของการรันแต่ละครั้งที่นี่อาจแตกต่างกันอาจจะ 1,000 system.out.println ("รันผลลัพธ์: counter.count =" + counter.count); -运行结果:Counter.count= 995
实际运算结果每次可能都不一样,本机的结果为:运行结果:Counter.count= 995 ,可以看出,在多线程的环境下,Counter.count并没有期望结果是1000
หลายคนคิดว่านี่เป็นปัญหาพร้อมกันหลายเธรด คุณจะต้องเพิ่ม volatile很多人以为,这个是多线程并发问题,只需要在变量count之前加上就可以避免这个问题,那我们在修改代码看看,看看结果是不是符合我们的期望
เคาน์เตอร์ระดับสาธารณะ {การนับจำนวน int คงที่ความผันผวนสาธารณะ = 0; Public Static Void Inc () {// ความล่าช้าที่นี่คือ 1 มิลลิวินาทีทำให้ผลลัพธ์เห็นได้ชัดว่าลอง {thread.sleep (1); } catch (interruptedException e) {} นับ ++; } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {// เริ่มต้น 1,000 เธรดในเวลาเดียวกันทำการคำนวณ i ++ และดูผลลัพธ์ที่แท้จริงสำหรับ (int i = 0; i <1000; i ++) {เธรดใหม่ } // ค่าของการรันแต่ละครั้งที่นี่อาจแตกต่างกันอาจเป็น 1,000 system.out.println ("รันผลลัพธ์: counter.count =" + counter.count); -ผลการทำงาน: counter.count = 992
ผลการดำเนินการยังไม่ถึง 1,000 เท่าที่เราคาดไว้ มาวิเคราะห์เหตุผลด้านล่าง
ในบทความคอลเลกชัน Java Garbage การจัดสรรหน่วยความจำในขณะที่ JVM อธิบายไว้ หนึ่งในพื้นที่หน่วยความจำคือสแต็กเครื่องเสมือน JVM และแต่ละเธรดมีสแต็กเธรดเมื่อทำงาน
สแต็กเธรดจะบันทึกข้อมูลค่าตัวแปรระหว่างรันไทม์เธรด เมื่อเธรดเข้าถึงค่าของวัตถุที่แน่นอนก่อนอื่นให้ค้นหาค่าของตัวแปรที่สอดคล้องกับหน่วยความจำ HEAP ผ่านการอ้างอิงของวัตถุจากนั้นใส่หน่วยความจำฮีป
ค่าเฉพาะของตัวแปรถูกโหลดลงในหน่วยความจำท้องถิ่นของเธรดและสำเนาของตัวแปรถูกสร้างขึ้น หลังจากนั้นเธรดจะไม่มีความสัมพันธ์ใด ๆ กับค่าตัวแปรของวัตถุในหน่วยความจำ HEAP อีกต่อไป แต่จะแก้ไขค่าของตัวแปรคัดลอกโดยตรง
ในช่วงเวลาหนึ่งหลังจากการแก้ไข (ก่อนที่เธรดจะออก) ค่าของการคัดลอกตัวแปรเธรดจะถูกเขียนโดยอัตโนมัติกลับไปยังตัวแปรวัตถุในฮีป วิธีนี้ค่าของวัตถุในกองจะเปลี่ยน ภาพต่อไปนี้
อธิบายปฏิสัมพันธ์การเขียนนี้
อ่านและโหลดตัวแปรคัดลอกจากหน่วยความจำหลักไปยังหน่วยความจำการทำงานปัจจุบัน
ใช้และกำหนดรหัสดำเนินการเพื่อเปลี่ยนค่าตัวแปรที่ใช้ร่วมกัน
จัดเก็บและเขียนเนื้อหาที่เกี่ยวข้องกับหน่วยความจำหลักรีเฟรชพร้อมข้อมูลหน่วยความจำที่ใช้งานได้
การใช้งานและการกำหนดสามารถปรากฏได้หลายครั้ง
อย่างไรก็ตามการดำเนินการเหล่านี้ไม่ใช่อะตอมนั่นคือหลังจากโหลดการอ่านหากตัวแปรนับหน่วยความจำหลักถูกแก้ไขค่าในหน่วยความจำการทำงานของเธรดจะไม่ทำให้เกิดการเปลี่ยนแปลงที่สอดคล้องกันเนื่องจากมีการโหลดดังนั้นผลลัพธ์ที่คำนวณจะแตกต่างจากที่คาดไว้
สำหรับตัวแปรที่แก้ไขโดยความผันผวนเครื่องเสมือน JVM จะมั่นใจได้ว่าค่าที่โหลดจากหน่วยความจำหลักไปยังหน่วยความจำการทำงานของเธรดเป็นล่าสุด
ตัวอย่างเช่นหากเธรด 1 และเธรด 2 กำลังดำเนินการอ่านและโหลดและพบว่าค่าการนับในหน่วยความจำหลักคือ 5 ค่าล่าสุดจะถูกโหลด
หลังจากการนับจำนวนฮีปถูกแก้ไขในเธรด 1 มันจะถูกเขียนลงในหน่วยความจำหลักและตัวแปรนับในหน่วยความจำหลักจะกลายเป็น 6
เนื่องจากเธรด 2 ได้ดำเนินการอ่านและโหลดแล้วค่าตัวแปรของจำนวนหน่วยความจำหลักจะได้รับการปรับปรุงเป็น 6 หลังจากการดำเนินการ
สิ่งนี้ทำให้เกิดขึ้นพร้อมกันหลังจากสองเธรดได้รับการแก้ไขด้วยคำหลักที่ผันผวนในเวลา
ขอบคุณสำหรับการอ่านฉันหวังว่ามันจะช่วยคุณได้ ขอบคุณสำหรับการสนับสนุนเว็บไซต์นี้!