Próbuję zrozumieć, co sprawia, że blokada współbieżności jest tak ważna, jeśli można jej użyć synchronized (this)
. W poniższym kodzie atrapy mogę wykonać:
- zsynchronizował całą metodę lub zsynchronizował wrażliwy obszar (
synchronized(this){...}
) - LUB zablokuj wrażliwy obszar kodu za pomocą ReentrantLock.
Kod:
private final ReentrantLock lock = new ReentrantLock();
private static List<Integer> ints;
public Integer getResult(String name) {
.
.
.
lock.lock();
try {
if (ints.size()==3) {
ints=null;
return -9;
}
for (int x=0; x<ints.size(); x++) {
System.out.println("["+name+"] "+x+"/"+ints.size()+". values >>>>"+ints.get(x));
}
} finally {
lock.unlock();
}
return random;
}
synchronized(this){synchronized(this){//some code}}
nie spowoduje martwej blokady. W przypadku wewnętrznej blokady, jeśli uzyskają monitor na zasobie i jeśli chcą go ponownie, mogą go uzyskać bez martwej blokady.Odpowiedzi:
ReentrantLock jest nieuporządkowane , w przeciwieństwie do
synchronized
konstrukcji - to znaczy, że nie trzeba używać strukturę blokową do blokowania, a nawet może posiadać blokadę całej metody. Przykład:Taki przepływ jest niemożliwy do przedstawienia za pomocą jednego monitora w
synchronized
konstrukcji.Oprócz tego
ReentrantLock
obsługuje odpytywanie blokady i blokada przerywana czeka na obsługę limitu czasu .ReentrantLock
obsługuje także konfigurowalną politykę uczciwości , umożliwiając bardziej elastyczne planowanie wątków.ReentrantLock
może być również bardziej skalowalny , działając znacznie lepiej przy większej rywalizacji. Możesz przeczytać więcej na ten temat tutaj .Twierdzenie to zostało jednak zakwestionowane; zobacz następujący komentarz:
Kiedy należy użyć
ReentrantLock
s? Zgodnie z tym artykułem developerWorks ...źródło
ReentrantLockPseudoRandom
kod w linku Lycog używa zupełnie nowych, niezamówionych blokad przy każdym wywołaniusetSeed
inext
ReentrantReadWriteLock
jest zamkiem specjalistycznym, natomiastsynchronized(this)
jest zamkiem ogólnego zastosowania. Są podobne, ale nie do końca takie same.Masz rację, że możesz użyć
synchronized(this)
zamiast,ReentrantReadWriteLock
ale nie zawsze jest odwrotnie.Jeśli chcesz lepiej zrozumieć, co sprawia, że
ReentrantReadWriteLock
specjalne wyszukiwanie zawiera informacje na temat synchronizacji wątków producent-konsument.Zasadniczo pamiętasz, że synchronizacja całymi metodami i synchronizacja ogólnego zastosowania (przy użyciu
synchronized
słowa kluczowego) mogą być używane w większości aplikacji bez zbytniego zastanawiania się nad semantyką synchronizacji, ale jeśli chcesz wycisnąć wydajność z kodu, może być konieczne poznaj inne, bardziej precyzyjne lub specjalne mechanizmy synchronizacji.Nawiasem mówiąc, używanie
synchronized(this)
- i ogólnie blokowanie za pomocą instancji klasy publicznej - może być problematyczne, ponieważ otwiera twój kod na potencjalne martwe blokady, ponieważ ktoś inny nieświadomie może spróbować zablokować twój obiekt gdzieś indziej w programie.źródło
public class MyLock { private final Object protectedLongLockingMonitor = new Object(); private long protectedLong = 0L; public void incrementProtectedLong() { synchronized(protectedLongLockingMonitor) { protectedLong++; } } }
Ze strony dokumentacji Oracle o ReentrantLock :
ReentrantLock jest własnością wątku ostatnia skutecznie blokujący, ale jeszcze nie odblokowania. Blokada wywołująca wątek powróci, po uzyskaniu blokady, gdy zamek nie jest własnością innego wątku. Metoda zwróci natychmiast, jeśli bieżący wątek jest już właścicielem blokady.
Konstruktor dla tej klasy akceptuje opcjonalny parametr uczciwości . Po ustawieniu wartości true, wbrew sprzeczkom, blokady sprzyjają przyznawaniu dostępu do najdłużej czekającego wątku . W przeciwnym razie ta blokada nie gwarantuje żadnego konkretnego zamówienia dostępu.
Najważniejsze funkcje ReentrantLock zgodnie z tym artykułem
Możesz użyć ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock, aby dalej uzyskać kontrolę nad szczegółowym blokowaniem operacji odczytu i zapisu.
Zapoznaj się z tym artykułem autorstwa Benjamana na temat używania różnego rodzaju blokad ReentrantLocks
źródło
Możesz użyć blokad ponownych wysyłek z polityką uczciwości lub limitem czasu, aby uniknąć głodu gwintu. Możesz zastosować zasadę uczciwości wątków. Pomoże to uniknąć ciągłego czekania na dostęp do zasobów.
„Polityka uczciwości” wybiera następny uruchamialny wątek do wykonania. Opiera się na priorytecie, czas od ostatniego uruchomienia, bla bla
Synchronizacja może również blokować w nieskończoność, jeśli nie można uciec z bloku. Reentrantlock może mieć ustawiony limit czasu.
źródło
Zsynchronizowane blokady nie oferują żadnego mechanizmu oczekiwania, w którym po wykonaniu jednego wątku dowolny wątek działający równolegle może uzyskać blokadę. Dzięki temu wątek znajdujący się w systemie i działający przez dłuższy czas nigdy nie ma szans na dostęp do udostępnionego zasobu, co prowadzi do głodu.
Blokady ponownego wysyłania są bardzo elastyczne i mają politykę uczciwości, w której jeśli wątek czeka przez dłuższy czas, a po zakończeniu aktualnie wykonywanego wątku możemy upewnić się, że dłuższy oczekujący wątek ma szansę na dostęp do udostępnionego zasobu, zmniejszając się w ten sposób przepustowość systemu i zwiększenie jego czasochłonności.
źródło
Załóżmy, że ten kod działa w wątku:
Ponieważ wątek posiada blokadę, pozwoli na wielokrotne wywołanie blokady (), więc ponownie wejdzie w blokadę. Można to osiągnąć za pomocą liczby referencyjnej, aby nie trzeba było ponownie uzyskiwać blokady.
źródło
Należy pamiętać, że:
nazwa „ ReentrantLock ” podaje niewłaściwy komunikat o innym mechanizmie blokującym, że nie są ponownie włączani. To nie jest prawda. Blokada uzyskana przez „zsynchronizowany” jest również ponownie uruchamiana w Javie.
Kluczowa różnica polega na tym, że „zsynchronizowany” korzysta z wewnętrznej blokady (takiej, którą posiada każdy obiekt), podczas gdy interfejs API blokady nie.
źródło
Myślę, że metody wait / powiadom / powiadom Wszystkie metody nie należą do klasy Object, ponieważ zanieczyszczają wszystkie obiekty metodami rzadko używanymi. Mają znacznie większy sens na dedykowanej klasie Lock. Z tego punktu widzenia być może lepiej jest użyć narzędzia specjalnie zaprojektowanego do danego zadania - tj. ReentrantLock.
źródło