0Pricing
Java Academy · บทเรียน

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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ReentrantLock กับ synchronized
  2. ReadWriteLock สำหรับสถานการณ์ผู้อ่าน-ผู้เขียน
  3. ตัวแปร Atomic: การอัปเดตแบบไร้ล็อก
  4. StampedLock และการอ่านเชิงคาดคะเน
← กลับไปที่ Java Academy