Giriş
Şu satırı dahil ederiz.
Key ve value olarak null değer verilemez. Doug Lea'nin açıklaması şöyle.
Tek bir lock ile korunan Collections.synchronizedMap yerine daha fazla lock kullanarak daha fazla ölçeklenebilirlik sağlamayı hedefliyor. Açıklaması şöyle
İç Yapısı
Java 8'den itibaren bu veriyapısına bir iyileştirme yapıldı. Eğer aynı bin içine düşen fazla sayıda nesne varsa, linked liste yerine artık balanced tree (yani red black tree) ile saklanıyor.
Şu satırı dahil ederiz.
import java.util.concurrent.ConcurrentHashMap;
Eğer istersek şu arayüzü kullanabiliriz.import java.util.concurrent.ConcurrentMap;
Yani şöyle yaparız.ConcurrentMap<String,String
> cache = new ConcurrentHashMap<>();
Null DeğerKey ve value olarak null değer verilemez. Doug Lea'nin açıklaması şöyle.
The main reason that nulls aren't allowed in ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) is that ambiguities that may be just barely tolerable in non-concurrent maps can't be accommodated. The main one is that if map.get(key) returns null, you can't detect whether the key explicitly maps to null vs the key isn't mapped. In a non-concurrent map, you can check this via map.contains(key), but in a concurrent one, the map might have changed between calls.Eğer mutlaka null kullanmamız gerekiyorsa value tarafında Optional kullanılabilir. Açıklaması şöyle.
A common solution is to use Optional (for pre-Java 8, use Guava's Optional) to represent the absence of a value.Lock Mekanizması
So your map would have a type ConcurrentHashMap<Key, Optional<Value>>.
Tek bir lock ile korunan Collections.synchronizedMap yerine daha fazla lock kullanarak daha fazla ölçeklenebilirlik sağlamayı hedefliyor. Açıklaması şöyle
partitions map into segments and lock them individually instead of locking the whole map.Bu konu hakkında yazılmış Java theory and practice: Building a better HashMap başlıklı yazı bilgilendirici.
İç Yapısı
Java 8'den itibaren bu veriyapısına bir iyileştirme yapıldı. Eğer aynı bin içine düşen fazla sayıda nesne varsa, linked liste yerine artık balanced tree (yani red black tree) ile saklanıyor.
The alternative String hash function added in 7u6 has been removed from JDK 8, along with the jdk.map.althashing.threshold system property. Instead, hash bins containing a large number of colliding keys improve performance by storing their entries in a balanced tree instead of a linked list. This JDK 8 change applies only to HashMap, LinkedHashMap, and ConcurrentHashMap.
Concurrent Kullanım Örnekleri
Örnek - Concurrent Set Olarak
Şöyle yaparız. Yani sorun olmuyor
Set<String> events = Collections.newSetFromMap(new ConcurrentHashMap<>());
events.add("1");
events.add("2");
for (String event : events) {
events.clear();
System.out.println(event);
}
Çıktısı şöyle
1 2
constructor
Şöyle yaparız.
concurrencyLevel kaç tane bucket yaratılacağını belirtir. Bu sayı sonrada değiştirilemez. Bu sayı verilmez ise değeri şöyledir.
ConcurrentHashMap computeX metodları yazısına taşıdım.
computeIfAbsent metodu - Key Yoksa Thread Safe Value İlklendirme
ConcurrentHashMap computeX metodları yazısına taşıdım.
computeIfPresent metodu - Key Varsa Thread Safe Value İlklendirme
ConcurrentHashMap computeX metodları yazısına taşıdım.
get metodu
İmzası şöyle
İmzası şöyle.
ConcurrentHashMap<String,String> cache = new ConcurrentHashMap<>();
constructor - initialCapacity + loadFactor + concurrencyLevelconcurrencyLevel kaç tane bucket yaratılacağını belirtir. Bu sayı sonrada değiştirilemez. Bu sayı verilmez ise değeri şöyledir.
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
compute metodu - Thread Safe İlklendirme ve GüncellemeConcurrentHashMap computeX metodları yazısına taşıdım.
computeIfAbsent metodu - Key Yoksa Thread Safe Value İlklendirme
ConcurrentHashMap computeX metodları yazısına taşıdım.
computeIfPresent metodu - Key Varsa Thread Safe Value İlklendirme
ConcurrentHashMap computeX metodları yazısına taşıdım.
get metodu
İmzası şöyle
public V get(Object key);
Şöyle yaparız.String key = ...
cache.get(key);
keySet metoduİmzası şöyle.
public ConcurrentHashMap.KeySet keySet(V mappedValue);
Açıklaması şöyle."Weakly consistent iterator" kelimesi ile şu kastediliyor. KeySetView nesnesini aldığımızda aslında bir snapshot alıyoruz. Bu seti dolaşırken ConcurrentHashMap değişebilir. Yani var olduğunu düşündüğümüz bir anahtar silinmiş olabilir.Returns a Set view of the keys contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. The set supports element removal, which removes the corresponding mapping from this map, via the Iterator.remove, Set.remove, removeAll, retainAll, and clear operations. It does not support the add or addAll operations.The view's iterators and spliterators are weakly consistent.
Örnek
Şu kodda hem map değişiyor hem de keyset'i dolaşıyoruz. Beklemediğimiz bir sonuç alınabilir.
Map<Long, Long> map = ...;
for (long key : map.keySet()) {
map.put(key, map.remove(key));
}
ÖrnekŞöyle yaparız.
for (String string : cache.keySet()) {
System.out.println(string + "," + map.get(string));
}
Iterator ile dolaşmamız sağlar. Şöyle yaparız.Iterator iterator = cache.keySet().iterator();
while (iterator.hasNext()) {
System.out.println(cache.get(iterator.next()));
}
ÖrnekAynı zamanda dönen Set'e ekleme yapılaiblir. Şöyle yaparız.
ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
Set<String> keySet = map.keySet("sameValue");
keySet.add("key1");
keySet.add("key2");
Bu kod şununla aynıdırConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
map.put("key1","sameValue");
map.put("key2","sameValue");
merge metodumerge metodu yazısına taşıdım
newKeySet metodu
Concurrent set döndürür. Şöyle yaparız.
Bu veri yapısınına key ve value değerleri null atanamaz. Açıklaması şöyle
Concurrent set döndürür. Şöyle yaparız.
Set<Object> seen = ConcurrentHashMap.newKeySet();
put metoduBu veri yapısınına key ve value değerleri null atanamaz. Açıklaması şöyle
Like Hashtable but unlike HashMap, this class does not allow null to be used as a key or value.
Örnek
Şu kod exception fırlatır.cache.put(null,"...");
putIfAbsent metoduAçıklaması şöyle.
- computeIfAbset() metodu gibi lambda almaz. Değeri direkt ister.If the specified key is not already associated with a value, associate it with the given value. This is equivalent toif (!map.containsKey(key)) return map.put(key, value); else return map.get(key);
except that the action is performed atomically.
- Eğer anahtar ilk defa ekleniyorsa null döner. Eğer anahtar varsa mevcut anahtar değerini döner.
- Değer olarak null verilebilir.
Örnek
Şöyle yaparız. Anahtar ilk defa eklendiği için null döner.
ConcurrentMap<String, String> concurrentMap = new ConcurrentHashMap<>();
String result = concurrentMap.putIfAbsent("AA", "BB");
System.out.println(result); // null
ÖrnekŞöyle yaparız.
List<Integer> mappedList = cachedMap.get(mapListKey);
if (mappedList == null) {
List<Integer> newMappedList = Lists.newArrayList();
mappedList = cachedMap.putIfAbsent(mapListKey, newMappedList);
if (mappedList == null) {
mappedList = newMappedList;
}
}
remove metoduAçıklaması şöyle.
Şöyle yaparız.Removes a single instance of the specified element from this collection, if it is present (optional operation).
String key = ...
cache.remove(key);
replace metoduVerilen anahtara ait değeri, yeni değer ile değiştirir. Eğer değiştirme başarılı ise true döner.
Örnek
Örnek
Şöyle yaparız.
private Integer somefunction() {
Integer oldOrder;
// Insert key if it isn't already present.
oldOrder = cache.putIfAbsent(key, 1);
if (oldOrder == null) {
return 0;
}
// If we get here, oldOrder holds the previous value.
// Atomically update it.
while (!cache.replace(key, oldOrder, oldOrder + 1)) {
oldOrder = count.get(key);
}
return oldOrder;
}
Hiç yorum yok:
Yorum Gönder