Współbieżność Java - interfejs ConcurrentMap

Interfejs java.util.concurrent.ConcurrentMap jest podinterfejsem interfejsu Map, obsługuje niepodzielne operacje na bazowej zmiennej mapy. Posiada metody pobierania i ustawiania, które działają jak odczyty i zapisy na zmiennych nietrwałych. Oznacza to, że zestaw ma relację zdarzenie przed każdym kolejnym uzyskaniem tej samej zmiennej. Ten interfejs zapewnia bezpieczeństwo wątków i gwarancje atomowości.

Metody ConcurrentMap

Sr.No. Metoda i opis
1

default V compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)

Próbuje obliczyć mapowanie dla określonego klucza i jego bieżącej zamapowanej wartości (lub null, jeśli nie ma bieżącego mapowania).

2

default V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)

Jeśli określony klucz nie jest już skojarzony z wartością (lub jest zamapowany na null), próbuje obliczyć jego wartość przy użyciu danej funkcji mapowania i wprowadza go do tej mapy, chyba że ma wartość null.

3

default V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)

Jeśli wartość dla określonego klucza jest obecna i inna niż null, próbuje obliczyć nowe mapowanie, biorąc pod uwagę klucz i jego bieżącą zamapowaną wartość.

4

default void forEach(BiConsumer<? super K,? super V> action)

Wykonuje daną akcję dla każdego wpisu w tej mapie, dopóki wszystkie wpisy nie zostaną przetworzone lub akcja zgłosi wyjątek.

5

default V getOrDefault(Object key, V defaultValue)

Zwraca wartość, na którą jest zamapowany określony klucz, lub defaultValue, jeśli ta mapa nie zawiera mapowania dla klucza.

6

default V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)

Jeśli określony klucz nie jest już powiązany z wartością lub jest powiązany z wartością null, kojarzy go z daną wartością inną niż null.

7

V putIfAbsent(K key, V value)

Jeśli określony klucz nie jest jeszcze powiązany z wartością, skojarz go z daną wartością.

8

boolean remove(Object key, Object value)

Usuwa wpis dla klucza tylko wtedy, gdy jest aktualnie mapowany na daną wartość.

9

V replace(K key, V value)

Zastępuje wpis dla klucza tylko wtedy, gdy jest aktualnie mapowany na jakąś wartość.

10

boolean replace(K key, V oldValue, V newValue)

Zastępuje wpis dla klucza tylko wtedy, gdy jest aktualnie mapowany na daną wartość.

11

default void replaceAll(BiFunction<? super K,? super V,? extends V> function)

Zastępuje wartość każdego wpisu wynikiem wywołania danej funkcji na tym wpisie, aż wszystkie wpisy zostaną przetworzone lub funkcja zgłosi wyjątek.

Przykład

Poniższy program TestThread przedstawia użycie ConcurrentMap vs HashMap.

import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class TestThread {

   public static void main(final String[] arguments) {
      Map<String,String> map = new ConcurrentHashMap<String, String>();

      map.put("1", "One");
      map.put("2", "Two");
      map.put("3", "Three");
      map.put("5", "Five");
      map.put("6", "Six");

      System.out.println("Initial ConcurrentHashMap: " + map);
      Iterator<String> iterator = map.keySet().iterator();

      try { 
         
         while(iterator.hasNext()) {
            String key = iterator.next();
            
            if(key.equals("3")) {
               map.put("4", "Four");
            }
         }
      } catch(ConcurrentModificationException cme) {
         cme.printStackTrace();
      }
      System.out.println("ConcurrentHashMap after modification: " + map);

      map = new HashMap<String, String>();

      map.put("1", "One");
      map.put("2", "Two");
      map.put("3", "Three");
      map.put("5", "Five");
      map.put("6", "Six");

      System.out.println("Initial HashMap: " + map);
      iterator = map.keySet().iterator();

      try {
         
         while(iterator.hasNext()) {
            String key = iterator.next();
            
            if(key.equals("3")) {
               map.put("4", "Four");
            }
         }
         System.out.println("HashMap after modification: " + map);
      } catch(ConcurrentModificationException cme) {
         cme.printStackTrace();
      }
   }  
}

Spowoduje to następujący wynik.

Wynik

Initial ConcurrentHashMap: {1 = One, 2 = Two, 3 = Three, 5 = Five, 6 = Six}
ConcurrentHashMap after modification: {1 = One, 2 = Two, 3 = Three, 4 = Four, 5 = Five, 6 = Six}
Initial HashMap: {1 = One, 2 = Two, 3 = Three, 5 = Five, 6 = Six}
java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextNode(Unknown Source)
	at java.util.HashMap$KeyIterator.next(Unknown Source)
	at TestThread.main(TestThread.java:48)