“สวัสดี อามีโก้!”
“สวัสดี เอลลี่!”
"ฉันอยากจะบอกคุณเกี่ยวกับตัวดัดแปลงที่ระเหยได้ คุณรู้หรือไม่ว่ามันคืออะไร"
"เกี่ยวอะไรกับด้าย ฉันจำไม่ได้แน่ชัด"
"จากนั้นฟัง นี่คือรายละเอียดทางเทคนิคสำหรับคุณ:"
"คอมพิวเตอร์มีหน่วยความจำสองประเภท: หน่วยความจำส่วนกลาง (ปกติ) และหน่วยความจำในตัวโปรเซสเซอร์ หน่วยความจำในตัวโปรเซสเซอร์แบ่งออกเป็นรีจิสเตอร์ แคชระดับแรก (L1) แคชระดับที่สอง (L2) และ ระดับสาม (L3)"
"หน่วยความจำประเภทนี้มีความเร็วต่างกัน หน่วยความจำที่เร็วและเล็กที่สุดคือรีจิสเตอร์ จากนั้นแคชโปรเซสเซอร์ (L1, L2, L3) และสุดท้ายคือหน่วยความจำส่วนกลาง (ช้าที่สุด)"
"หน่วยความจำส่วนกลางและแคชของโปรเซสเซอร์ทำงานที่ความเร็วต่างกันอย่างมาก ดังนั้นเครื่อง Java จึงอนุญาตให้แต่ละเธรดจัดเก็บตัวแปรที่ใช้บ่อยที่สุดในหน่วยความจำเธรดภายในเครื่อง (ในแคชของโปรเซสเซอร์)"
"กระบวนการนี้สามารถควบคุมได้หรือไม่"
"ไม่จริง งานทั้งหมดทำโดยเครื่อง Java มันฉลาดมากเมื่อพูดถึงการปรับประสิทธิภาพให้เหมาะสม"
"แต่นี่คือเหตุผลที่ฉันบอกคุณนี้ มีปัญหาเล็ก ๆ อย่างหนึ่ง เมื่อสองเธรดทำงานกับตัวแปรเดียวกัน แต่ละเธรดสามารถเก็บสำเนาไว้ในแคชในเครื่องของตัวเอง จากนั้นเธรดหนึ่งอาจเปลี่ยนตัวแปร แต่เธรดที่สอง อาจไม่เห็นการเปลี่ยนแปลง เนื่องจากยังคงทำงานกับสำเนาของตัวแปรของตัวเอง"
“อืม แล้วจะทำอะไรได้ล่ะ”
"ผู้สร้างของ Java ให้คำหลักพิเศษสำหรับสถานการณ์นี้: volatile หากมีการเข้าถึงตัวแปรจากเธรดที่แตกต่างกัน คุณต้องทำเครื่องหมายด้วยตัวดัดแปลง volatile ดังนั้นเครื่อง Java จะไม่ใส่ลงในแคช นี่เป็นวิธีการปกติ ดู:"
public volatile int count = 0;
“อ๋อ ฉันจำได้ เธอเคยพูดเรื่องนี้แล้ว ฉันรู้เรื่องนี้แล้ว”
“แน่ใจ แต่เธอจำได้ก็ต่อเมื่อฉันบอกคุณเท่านั้น”
“เอ่อ ลืมไปนิดนึง”
"การทำซ้ำคือแม่ของการเรียนรู้!"
"ต่อไปนี้เป็นข้อเท็จจริงใหม่บางประการเกี่ยวกับตัวดัดแปลงที่ระเหยได้ ตัวดัดแปลงที่ระเหยได้รับประกันว่าตัวแปรจะถูกอ่านและเขียนอย่างปลอดภัยเท่านั้น ไม่ได้รับประกันว่าจะเปลี่ยนแปลงได้อย่างปลอดภัย"
"อะไรคือความแตกต่าง?"
"ดูว่าตัวแปรมีการเปลี่ยนแปลงอย่างไร:"
รหัส | เกิดอะไรขึ้นจริง: | คำอธิบาย |
---|---|---|
|
|
ขั้นตอนที่ 1 ค่าจำนวนตัวแปรถูกคัดลอกจากหน่วยความจำส่วนกลางไปยังรีจิสเตอร์ตัวประมวลผล ขั้นตอนที่ 2 ขั้นตอนที่ 3 |
"ว้าว! ตัวแปรทั้งหมดถูกเปลี่ยนในโปรเซสเซอร์เท่านั้นเหรอ?"
"ใช่."
"และค่าจะถูกคัดลอกไปมา: จากหน่วยความจำไปยังโปรเซสเซอร์และย้อนกลับ"
"ใช่."
"โมดิฟายเออร์ระเหยรับประกันว่าเมื่อมีการเข้าถึงจำนวนตัวแปร มันจะถูกอ่านจากหน่วยความจำ (ขั้นตอนที่ 1) และถ้าเธรดต้องการกำหนดค่าใหม่ มันจะอยู่ในหน่วยความจำส่วนกลางอย่างแน่นอน (ขั้นตอนที่ 3)"
"แต่เครื่อง Java ไม่รับประกันว่าจะไม่มีการสลับเธรดระหว่างขั้นตอนที่ 1 และ 3"
"ดังนั้น การเพิ่มตัวแปรทีละ 1 จึงเป็นการดำเนินการ 3 รายการจริงหรือ"
"ใช่."
"และหากเธรดสองเธรดต้องการดำเนินการ count++ พร้อมกัน เธรดเหล่านั้นอาจรบกวนซึ่งกันและกันได้"
"ใช่ ลองดูสิ:"
หัวข้อที่ 1 | หัวข้อที่ 2 | ผลลัพธ์ |
---|---|---|
|
|
|
"คุณสามารถเข้าถึงตัวแปรได้ แต่การเปลี่ยนแปลงยังคงมีความเสี่ยงอยู่ใช่ไหม"
"ก็เปลี่ยนได้นะ ระวังหน่อย ☺"
"ยังไง?"
" ซิงโครไนซ์ คือเพื่อนที่ดีที่สุดของเรา"
"ฉันเห็น."