/ / Jak uzyskać prawdziwie atomową aktualizację dla TrieMap.getOrElseUpdate - scala, concurrency, compare-and-swap

Jak uzyskać prawdziwie atomową aktualizację dla TrieMap.getOrElseUpdate - scala, concurrency, compare-and-swap

Jak rozumiem, TrieMap.getOrElseUpdate nadal nie jest prawdziwie atomowy, i to naprawia tylko zwrócony wynik (może zwrócić różne instancje dla różnych wywołań przed tą poprawką), więc funkcja Updater może wciąż być wywoływana kilka razy, ponieważ dokumentacja (dla 2.11.7) mówi:

Uwaga: Ta metoda wywoła operację op co najwyżej raz. Jednak operacja op może zostać wywołana bez dodawania wyniku do mapy, jeśli współbieżny proces próbuje również dodać wartość odpowiadającą temu samemu kluczowi k.

* Sprawdziłem to ręcznie dla wersji 2.11.7, wciąż "co najmniej raz"

Jak zagwarantować jednorazowe połączenie (jeśli używam TrieMap dla fabryk)?

Odpowiedzi:

1 dla odpowiedzi № 1

Myślę, że to rozwiązanie powinno działać zgodnie z moimi wymaganiami:

trait LazyComp { val get: Int }

val map = new TrieMap[String, LazyComp]()

val count = new AtomicInteger() //just for test, you don"t need it

def getSingleton(key: String) = {
val v = new LazyComp {
lazy val get = {
//compute something
count.incrementAndGet() //just for test, you don"t need it
}
}
map.putIfAbsent(key, v).getOrElse(v).get
}

Wierzę, lazy val faktycznie korzysta z podwójnie sprawdzonego zsynchronizowanego wnętrza. Również kod wewnątrz powinien być bezpieczny od wyjątków

Wydajność może jednak poprawić się w przyszłości: SIP-20

Test:

scala> (0 to 10000000).par.map(_ => getSingleton("zzz")).last
res8: Int = 1

P.S. Java ma computeIfAbscent metoda włączona ConcurrentHashMap które również mogę wykorzystać.