StampedLock และการอ่านเชิงคาดคะเน
ประยุกต์ใช้โหมดการอ่านเชิงคาดคะเนของ StampedLock กับงานปริมาณสูงที่เน้นการอ่าน
StampedLock และการอ่านเชิงคาดคะเน เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
StampedLock คืออะไร
StampedLock เปิดตัวใน Java 8 โดยต่อยอดแนวคิดของ ReadWriteLock ด้วยโหมด การอ่านแบบคาดการณ์ เพิ่มเติม การดำเนินการจะคืนค่า long ที่เป็น หมายเลขประทับ ซึ่งใช้สำหรับปล่อยล็อกหรือตรวจสอบการอ่านแบบคาดการณ์
import java.util.concurrent.locks.*;
StampedLock sl = new StampedLock();
// Exclusive write:
long stamp = sl.writeLock();
try {
// write data
} finally {
sl.unlockWrite(stamp);
}
// Shared read:
stamp = sl.readLock();
try {
// read data
} finally {
sl.unlockRead(stamp);
}โหมดการอ่านแบบคาดการณ์
การอ่านแบบคาดการณ์จะไม่ใช้ล็อก เพียงรับหมายเลขประทับมาเท่านั้น หลังอ่านเสร็จให้ตรวจสอบหมายเลขประทับ หากการตรวจสอบล้มเหลว (มีผู้เขียนเข้ามาแทรก) ให้เปลี่ยนไปใช้ล็อกอ่านจริง:
StampedLock sl2 = new StampedLock();
double x = 0, y = 0;
// Try optimistic read first:
long stamp = sl2.tryOptimisticRead();
double localX = x, localY = y; // read values
if (!sl2.validate(stamp)) {
// A write occurred — fall back to read lock
stamp = sl2.readLock();
try {
localX = x;
localY = y;
} finally {
sl2.unlockRead(stamp);
}
}
// use localX and localYตัวอย่างจุดสองมิติแบบเต็ม
ตัวอย่าง StampedLock แบบคลาสสิก — จุดสองมิติที่ใช้การอ่านแบบคาดการณ์:
class Point {
private double x, y;
private final StampedLock lock = new StampedLock();
void move(double dx, double dy) {
long stamp = lock.writeLock();
try { x += dx; y += dy; }
finally { lock.unlockWrite(stamp); }
}
double distanceFromOrigin() {
long stamp = lock.tryOptimisticRead();
double cx = x, cy = y;
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try { cx = x; cy = y; }
finally { lock.unlockRead(stamp); }
}
return Math.sqrt(cx * cx + cy * cy);
}
}การแปลงโหมดล็อก
StampedLock รองรับการแปลงระหว่างโหมดล็อก:
StampedLock sl3 = new StampedLock();
// Read → Write upgrade attempt:
long readStamp = sl3.readLock();
long writeStamp = sl3.tryConvertToWriteLock(readStamp);
if (writeStamp != 0) {
// Successfully upgraded!
// ... write ...
sl3.unlockWrite(writeStamp);
} else {
// Upgrade failed — release read and reacquire write
sl3.unlockRead(readStamp);
writeStamp = sl3.writeLock();
// ... write ...
sl3.unlockWrite(writeStamp);
}การอ่านแบบคาดการณ์มีประโยชน์มากที่สุดเมื่อใด
การอ่านแบบคาดการณ์เหมาะอย่างยิ่งเมื่อ:
- มีการอ่านบ่อยกว่าการเขียนอย่างมาก
- สแนปช็อตข้อมูลเก็บอยู่ในตัวแปรภายในไม่กี่ตัว (ไม่ต้องจัดสรรอ็อบเจ็กต์)
- การแย่งทรัพยากรจากการเขียนต่ำ (การตรวจสอบล้มเหลวไม่บ่อย)
หากมีการเขียนบ่อย การอ่านแบบคาดการณ์จะเปลี่ยนไปใช้ล็อกอ่านเต็มรูปแบบซ้ำ ๆ จึงไม่ก่อให้เกิดประโยชน์
StampedLock เทียบกับ ReadWriteLock
ความแตกต่างสำคัญ:
- StampedLock: เพิ่มการอ่านแบบคาดการณ์ ไม่รองรับการเข้าล็อกซ้ำ และไม่รองรับเงื่อนไข
- ReentrantReadWriteLock: รองรับการเข้าล็อกซ้ำ รองรับเงื่อนไข และไม่มีโหมดการอ่านแบบคาดการณ์
StampedLock เร็วกว่าเมื่อการแย่งทรัพยากรจากการเขียนต่ำ ส่วน ReentrantReadWriteLock ปลอดภัยกว่าและมีความสามารถมากกว่า
StampedLock ไม่รองรับการเข้าล็อกซ้ำ
ต่างจาก ReentrantLock ตรงที่ StampedLock ไม่รองรับการเข้าล็อกซ้ำ เธรดที่พยายามได้มาซึ่งโหมดที่ตนเองถืออยู่แล้วจะเกิดการติดตาย:
StampedLock sl4 = new StampedLock();
long s1 = sl4.readLock();
// DO NOT: sl4.readLock() again — deadlocks with non-reentrant!tryWriteLock และ tryReadLock
การพยายามได้มาซึ่งล็อกโดยไม่บล็อกจะคืนค่า 0 หากไม่สำเร็จ:
StampedLock sl5 = new StampedLock();
long stamp = sl5.tryWriteLock();
if (stamp != 0) {
try {
System.out.println("Got write lock");
} finally {
sl5.unlockWrite(stamp);
}
} else {
System.out.println("Write lock unavailable");
}การใช้เป็น ReadWriteLock
StampedLock สามารถคืนมุมมองเป็น ReadWriteLock มาตรฐานเพื่อความเข้ากันได้:
StampedLock sl6 = new StampedLock();
Lock readLock = sl6.asReadLock();
Lock writeLock = sl6.asWriteLock();
ReadWriteLock rwView = sl6.asReadWriteLock();
// These provide standard Lock interface without optimistic modeแนวคิดจากการวัดประสิทธิภาพ
ผลการวัดประสิทธิภาพโดยทั่วไปแสดงให้เห็นว่า:
- มีการอ่านเป็นส่วนใหญ่มาก (อ่าน 99%): StampedLock > ReadWriteLock > การล็อกอัตโนมัติ
- งานแบบผสม (อ่าน 70%): ReadWriteLock ≈ StampedLock
- มีการเขียนเป็นส่วนใหญ่: การล็อกอัตโนมัติหรือ ReentrantLock มักชนะ (มีค่าใช้จ่ายน้อยกว่า)
ควรวัดประสิทธิภาพด้วยลักษณะงานที่สมจริงก่อนปรับปรุงประสิทธิภาพเสมอ
ความไม่ถูกต้องของหมายเลขประทับหลังปลดล็อก
หลังจากปล่อยล็อกด้วยหมายเลขประทับ หมายเลขนั้นจะไม่ถูกต้อง การใช้หมายเลขประทับเก่าหลังปลดล็อกนำไปสู่พฤติกรรมที่ไม่ได้กำหนดไว้ — ให้เก็บหมายเลขประทับใหม่ทุกครั้งที่ได้มาซึ่งล็อก
StampedLock sl7 = new StampedLock();
long stamp = sl7.writeLock();
sl7.unlockWrite(stamp);
// stamp is now invalid — don't use it:
// sl7.unlockWrite(stamp); // throws IllegalMonitorStateException or corrupts stateตรวจสอบอย่างรวดเร็ว
การอ่านแบบคาดการณ์ด้วย tryOptimisticRead() และการเรียก validate(stamp) ในภายหลังคืนค่าเป็นเท็จ โค้ดควรทำอะไรต่อ
สรุป: StampedLock
ประเด็นสำคัญ:
- มีสามโหมด ได้แก่ การอ่านแบบคาดการณ์ (ไม่ใช้ล็อก) ล็อกอ่าน และล็อกเขียน
- tryOptimisticRead() + validate() — ความพยายามอ่านที่แทบไม่มีค่าใช้จ่าย
- เมื่อตรวจสอบล้มเหลว → เปลี่ยนไปใช้ readLock()
- ไม่รองรับการเข้าล็อกซ้ำ — เสี่ยงเกิดการติดตายหากเธรดเดิมได้มาซึ่งล็อกอีกครั้ง
- ไม่รองรับเงื่อนไข — ใช้ ReentrantReadWriteLock เมื่อจำเป็น
คำถามที่พบบ่อย
บทเรียน “StampedLock และการอ่านเชิงคาดคะเน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “StampedLock และการอ่านเชิงคาดคะเน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “StampedLock และการอ่านเชิงคาดคะเน”
ประยุกต์ใช้โหมดการอ่านเชิงคาดคะเนของ StampedLock กับงานปริมาณสูงที่เน้นการอ่าน คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “StampedLock และการอ่านเชิงคาดคะเน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ReentrantLock กับ synchronized
- ReadWriteLock สำหรับสถานการณ์ผู้อ่าน-ผู้เขียน
- ตัวแปร Atomic: การอัปเดตแบบไร้ล็อก
- StampedLock และการอ่านเชิงคาดคะเน