0Pricing
Java Academy · Lekcja

StampedLock i optymistyczne odczyty

Stosuj tryb optymistycznego odczytu StampedLock w zadaniach o dużej przepustowości, z przewagą odczytów.

StampedLock i optymistyczne odczyty to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.

Czym jest StampedLock?

Wprowadzony w Javie 8 element StampedLock rozwija koncepcję ReadWriteLock o dodatkowy tryb optymistycznego odczytu. Operacje zwracają wartość typu long, czyli znacznik, używaną do zwolnienia blokady lub sprawdzenia poprawności optymistycznego odczytu.

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);
}

Tryb optymistycznego odczytu

Optymistyczny odczyt nie uzyskuje żadnej blokady — jedynie pobiera znacznik. Po odczycie należy sprawdzić poprawność znacznika. Jeśli sprawdzenie się nie powiedzie (w międzyczasie zadziałał autor zapisu), należy przejść na rzeczywistą blokadę odczytu:

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

Pełny przykład Point2D

Klasyczny przykład użycia StampedLock — punkt 2D z optymistycznymi odczytami:

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);
    }
}

Konwersja blokady

StampedLock obsługuje konwersję między trybami blokady:

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);
}

Kiedy optymistyczne odczyty są najbardziej korzystne

Optymistyczne odczyty sprawdzają się najlepiej, gdy:

  • odczyty występują znacznie częściej niż zapisy
  • migawka danych mieści się w kilku zmiennych lokalnych (bez alokowania obiektu)
  • rywalizacja podczas zapisu jest niewielka (sprawdzenie poprawności rzadko kończy się niepowodzeniem)

Jeśli zapisy występują często, optymistyczne odczyty wielokrotnie przechodzą na pełne blokady odczytu — nie przynosząc żadnych korzyści.

StampedLock a ReadWriteLock

Najważniejsze różnice:

  • StampedLock: dodaje optymistyczne odczyty; NIE jest reentrantny; nie obsługuje Condition
  • ReentrantReadWriteLock: jest reentrantny; obsługuje Condition; nie ma trybu optymistycznego

StampedLock jest szybszy przy niewielkiej rywalizacji podczas zapisu. ReentrantReadWriteLock jest bezpieczniejszy i oferuje więcej funkcji.

StampedLock NIE jest reentrantny

W przeciwieństwie do ReentrantLock, StampedLock NIE jest reentrantny. Wątek próbujący uzyskać tryb, który już posiada, spowoduje zakleszczenie:

StampedLock sl4 = new StampedLock();
long s1 = sl4.readLock();
// DO NOT: sl4.readLock() again — deadlocks with non-reentrant!

tryWriteLock i tryReadLock

Nieblokujące próby uzyskania blokady zwracają 0 w przypadku niepowodzenia:

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");
}

Używanie jako ReadWriteLock

StampedLock może zwrócić widok w postaci standardowego ReadWriteLock na potrzeby zgodności:

StampedLock sl6 = new StampedLock();
Lock readLock  = sl6.asReadLock();
Lock writeLock = sl6.asWriteLock();
ReadWriteLock rwView = sl6.asReadWriteLock();
// These provide standard Lock interface without optimistic mode

Intuicja dotycząca testów wydajnościowych

Wyniki testów wydajnościowych zazwyczaj pokazują:

  • zdecydowana przewaga odczytów (99% odczytów): StampedLock > ReadWriteLock > synchronized
  • mieszane obciążenie (70% odczytów): ReadWriteLock ≈ StampedLock
  • przewaga zapisów: synchronized lub ReentrantLock często wygrywa (mniejszy narzut)

Przed optymalizacją należy zawsze wykonać profilowanie z użyciem realistycznych obciążeń.

Nieważność znacznika po odblokowaniu

Po zwolnieniu blokady za pomocą znacznika znacznik ten staje się nieważny. Użycie starego znacznika po odblokowaniu prowadzi do nieokreślonego zachowania — należy zawsze pobierać nowy znacznik przy każdym uzyskaniu blokady.

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

Szybkie sprawdzenie

Optymistyczny odczyt za pomocą tryOptimisticRead(), po którym następuje validate(stamp), zwraca false. Co kod powinien zrobić następnie?

Podsumowanie: StampedLock

Najważniejsze informacje:

  • Trzy tryby: optymistyczny odczyt (bez blokady), blokada odczytu i blokada zapisu
  • tryOptimisticRead() + validate() — próba odczytu bez narzutu
  • W przypadku niepowodzenia sprawdzenia poprawności → przejście na readLock()
  • NIE jest reentrantny — ponowne uzyskanie blokady przez ten sam wątek grozi zakleszczeniem
  • Brak obsługi Condition — gdy jest potrzebna, należy użyć ReentrantReadWriteLock

Często zadawane pytania

Czy lekcja „StampedLock i optymistyczne odczyty” jest bezpłatna?

Tak — pełny tekst „StampedLock i optymistyczne odczyty” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „StampedLock i optymistyczne odczyty”?

Stosuj tryb optymistycznego odczytu StampedLock w zadaniach o dużej przepustowości, z przewagą odczytów. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Java Academy?

Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „StampedLock i optymistyczne odczyty”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?

Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. ReentrantLock a synchronized
  2. ReadWriteLock w scenariuszach czytelnik-pisarz
  3. Zmienne atomowe: aktualizacje bez blokad
  4. StampedLock i optymistyczne odczyty
← Powrót do Java Academy