8

Java guruConcurrentHashMap vs ReentrantReadWriteLock opartej własną mapę do przeładunku

Obecnie mamy HashMap<String,SomeApplicationObject> który jest czytać często i modyfikowane sporadycznie a my mamy problemy, które w trakcie modyfikacji/przeładunek, Czytaj zwrotów pracy null co jest niedopuszczalne.

Aby rozwiązać ten problem mam następujące opcje:

A. Użyj ConcurrentHashMap

Która wygląda pierwszy wybór, ale działania, które mówimy o to reload() - oznacza clear() następnie replaceAll(). Więc jeśli Map jest czytany po clear() i pre replaceAll(), zwraca null, co nie jest pożądane. Nawet jeśli I synchronize to nie rozwiąże problemu.

B. Utwórz kolejną realizację w oparciu ReentrantReadWriteLock

Gdzie mogę tworzyć posiadły Write Lock przed reload() operacji. Wydaje się to bardziej odpowiednie, ale wydaje mi się, że musi istnieć coś, co jest już do tego dostępne i nie muszę wymyślać koła.

Jakie jest najlepsze wyjście?

EDIT Czy jakakolwiek kolekcja jest już dostępna z taką funkcją?

+0

Twoje mapy są praktycznie niezmienne, co czyni je idealnym celem do publikowania za pomocą 'volatile'. –

+0

** Efektywnie niezmienny ** przepraszam Nie rozumiem 'niezmiennego' tak dobrze ... Czy mógłbyś podać jakieś wskazówki ??? – SiB

Odpowiedz

4

Wygląda na to, że nie jesteś pewien, w jaki sposób można zasugerować, co sugeruje Peter Lawrey. To może wyglądać następująco:

class YourClass { 
    private volatile Map<String, SomeApplicationObject> map; 

    //constructors etc. 

    public void reload() { 
     Map<String,SomeApplicationObject> newMap = getNewValues(); 
     map = Collections.unmodifiableMap(newMap); 
    } 
} 

Nie ma problemów współbieżności, ponieważ:

  • Nowa mapa jest tworzona za pomocą zmiennej lokalnej, która z definicji nie jest dzielona - getNewValues nie musi być zsynchronizowane lub atomowej
  • ASSIGNMENT do map jest atomowy
  • map jest lotny, który gwarantuje, że inne wątki będą obserwować zmiany
8

Odświeżając mapę, chciałbym ją wymienić po ponownym wczytaniu.

Można to zrobić za pomocą ulotnej mapy, którą zastępuje się w całości po aktualizacji.

+0

czy mógłbyś wyjaśnić więcej szczegółów? Trudno mi zrozumieć, dlaczego to zadziała. Rozumiem, że lotny gwarantuje widoczność, ale jak działa złożona operacja, jak wyczyść niż replaceAll? Dziękuję Ci. – Eugene

+0

Aby zastąpić całą mapę, wystarczy, że po utworzeniu nowej kopii przypiszesz nową mapę do starego ulotnego odniesienia w swoim polu. to znaczy, że naprawdę wymieniasz wszystkie, nawet samą mapę, nie tylko jej zawartość. –

5

To brzmi jak lot jak Guava'sCache, ale to naprawdę zależy od tego, jak wypełniasz mapę i jak obliczyć wartości. (Ujawnienie: wnoszę wkład w Guava.)

Prawdziwe pytanie brzmi, czy możesz określić sposób obliczania swojego SomeApplicationObject na podstawie danych wejściowych String. Tylko na podstawie tego, co pan powiedział nam tak daleko, może to wyglądać mniej więcej tak ...

LoadingCache<String, SomeApplicationObject> cache = CacheBuilder.newBuilder() 
    .build(
     new CacheLoader<String, SomeApplicationObject>() { 
     public SomeApplicationObject load(String key) throws AnyException { 
      return computeSomeApplicationObject(key); 
     } 
     }); 

Potem, kiedy tylko chciał odbudować cache, wystarczy zadzwonić cache.invalidateAll(). Przy pomocy LoadingCache można wtedy zadzwonić pod numer cache.get(key), a jeśli jeszcze nie obliczył on wartości, zostanie on ponownie obliczony. A może po zadzwonieniu pod numer cache.invalidateAll() możesz zadzwonić pod numer cache.loadAll(allKeys), ale nadal musisz mieć możliwość ładowania pojedynczych elementów naraz, na wypadek gdyby pojawiły się zapytania między invalidateAll i loadAll.

Jeśli jest to niedopuszczalne - jeśli nie możesz załadować jednej wartości osobno, musisz załadować je wszystkie naraz - wtedy pójdę dalej z podejściem Petera Lawrey'a - zachowaj odniesienie do numeru volatile mapuj (najlepiej ImmutableMap), przelicz całą mapę i przypisz nową mapę do referencji, gdy skończysz.

+0

SomeApplicationObject jest jednostką, która jest wstępnie ładowana z bazy danych podczas uruchamiania aplikacji i odczytu z mapy przez cały czas ... Czasami administrator systemu może ponownie załadować wartości. – SiB

Powiązane problemy