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 localYPeł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 modeIntuicja 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 stateSzybkie 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
- ReentrantLock a synchronized
- ReadWriteLock w scenariuszach czytelnik-pisarz
- Zmienne atomowe: aktualizacje bez blokad
- StampedLock i optymistyczne odczyty