在本教程中,我們將借助示例學(xué)習(xí)Java ConcurrentHashMap類及其操作。
Java集合框架的ConcurrentHashMap類提供了線程安全的映射。 也就是說,多個線程可以一次訪問該映射,而不會影響映射中條目的一致性。
它繼承了ConcurrentMap接口。
為了創(chuàng)建并發(fā)的哈希圖,我們必須先導(dǎo)入java.util.concurrent.ConcurrentHashMap包。導(dǎo)入包后,就可以在Java中創(chuàng)建并發(fā)哈希映射。
//ConcurrentHashMap具有容量8和負(fù)載因子0.6 ConcurrentHashMap<Key, Value> numbers = new ConcurrentHashMap<>(8, 0.6f);
在上面的代碼中,我們創(chuàng)建了一個名為numbers的并發(fā)哈希映射。
這里,
Key - 用于關(guān)聯(lián)map中每個元素(值)的唯一標(biāo)識符
Value - map中與鍵相關(guān)聯(lián)的元素
注意語句 new ConcurrentHashMap<>(8, 0.6)。在這里,第一個參數(shù)是capacity,第二個參數(shù)是loadFactor。
capacity -該映射的容量為8。意味著,它可以存儲8個條目。
loadFactor-此map的負(fù)載因子為0.6。這意味著,只要我們的哈希表填充了60%,條目就會移到新哈希表中,其大小是原始哈希表的兩倍。
默認(rèn)容量和負(fù)載因子
無需定義其容量和負(fù)載因子就可以創(chuàng)建并發(fā)哈希圖。例如,
// 具有默認(rèn)容量和負(fù)載因子的ConcurrentHashMap ConcurrentHashMap<Key, Value> numbers1 = new ConcurrentHashMap<>();
默認(rèn),
map的容量將為 16
負(fù)載因子將為 0.75
這是我們?nèi)绾蝿?chuàng)建包含其他映射的所有元素的并發(fā)哈希映射。
import java.util.concurrent.ConcurrentHashMap; import java.util.HashMap; class Main { public static void main(String[] args) { // 創(chuàng)建偶數(shù)的hashmap HashMap<String, Integer> evenNumbers = new HashMap<>(); evenNumbers.put("Two", 2); evenNumbers.put("Four", 4); System.out.println("HashMap: " + evenNumbers); //從其他映射創(chuàng)建并發(fā)hashmap ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>(evenNumbers); numbers.put("Three", 3); System.out.println("ConcurrentHashMap: " + numbers); } }
輸出結(jié)果
HashMap: {Four=4, Two=2} ConcurrentHashMap: {Four=4, Two=2, Three=3}
ConcurrentHashMap類提供了允許我們在映射上執(zhí)行各種操作的方法。
put() - 將指定的鍵/值映射插入到映射中
putAll() - 將指定映射的所有條目插入此map
putIfAbsent() - 如果映射中不存在指定的鍵,則將指定的鍵/值映射插入到map中
例如,
import java.util.concurrent.ConcurrentHashMap; class Main { public static void main(String[] args) { //創(chuàng)建偶數(shù)的ConcurrentHashMap ConcurrentHashMap<String, Integer> evenNumbers = new ConcurrentHashMap<>(); // 使用 put() evenNumbers.put("Two", 2); evenNumbers.put("Four", 4); // 使用 putIfAbsent() evenNumbers.putIfAbsent("Six", 6); System.out.println("偶數(shù)的ConcurrentHashMap: " + evenNumbers); //Creating ConcurrentHashMap of numbers ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>(); numbers.put("One", 1); // 使用 putAll() numbers.putAll(evenNumbers); System.out.println("ConcurrentHashMap的數(shù)字為: " + numbers); } }
輸出結(jié)果
偶數(shù)的ConcurrentHashMap: {Six=6, Four=4, Two=2} ConcurrentHashMap的數(shù)字為: {Six=6, One=1, Four=-4, Two=2}
1.使用entrySet(),keySet()和values()
entrySet() - 返回一組所有鍵/值映射的集合
keySet() - 返回map所有鍵的集合
values() - 返回map所有值的集合
例如,
import java.util.concurrent.ConcurrentHashMap; class Main { public static void main(String[] args) { ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>(); numbers.put("One", 1); numbers.put("Two", 2); numbers.put("Three", 3); System.out.println("ConcurrentHashMap: " + numbers); // 使用 entrySet() System.out.println("Key/Value 映射: " + numbers.entrySet()); // 使用 keySet() System.out.println("Keys: " + numbers.keySet()); // 使用 values() System.out.println("Values: " + numbers.values()); } }
輸出結(jié)果
ConcurrentHashMap: {One=1, Two=2, Three=3} Key/Value 映射: [One=1, Two=2, Three=3] Keys: [One, Two, Three] Values: [1, 2, 3]
2.使用get()和getOrDefault()
get() - 返回與指定鍵關(guān)聯(lián)的值。如果找不到鍵,則返回null。
getOrDefault() - 返回與指定鍵關(guān)聯(lián)的值。如果找不到鍵,則返回指定的默認(rèn)值。
例如,
import java.util.concurrent.ConcurrentHashMap; class Main { public static void main(String[] args) { ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>(); numbers.put("One", 1); numbers.put("Two", 2); numbers.put("Three", 3); System.out.println("ConcurrentHashMap: " + numbers); // 使用 get() int value1 = numbers.get("Three"); System.out.println("使用get(): " + value1); // 使用 getOrDefault() int value2 = numbers.getOrDefault("Five", 5); System.out.println("使用getOrDefault(): " + value2); } }
輸出結(jié)果
ConcurrentHashMap: {One=1, Two=2, Three=3} 使用get(): 3 使用getOrDefault(): 5
remove(key) - 返回并從映射中刪除與指定鍵關(guān)聯(lián)的條目
remove(key, value) - 僅當(dāng)指定鍵映射到指定值并返回布爾值時,才從映射中刪除條目
例如,
import java.util.concurrent.ConcurrentHashMap; class Main { public static void main(String[] args) { ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>(); numbers.put("One", 1); numbers.put("Two", 2); numbers.put("Three", 3); System.out.println("ConcurrentHashMap: " + numbers); //單參數(shù)刪除方法 int value = numbers.remove("Two"); System.out.println("被刪除的值: " + value); // 具有兩個參數(shù)的刪除方法 boolean result = numbers.remove("Three", 3); System.out.println("條目 {Three=3} 被刪除? " + result); System.out.println("更新后的ConcurrentHashMap: " + numbers); } }
輸出結(jié)果
ConcurrentHashMap: {One=1, Two=2, Three=3} 被刪除的值: 2 條目 {Three=3} 被刪除? True 更新后的ConcurrentHashMap: {One=1}
ConcurrentHashMap類提供了可以安全地應(yīng)用于并行的map不同的批量操作方法。
forEach()方法遍歷我們的條目并執(zhí)行指定的函數(shù)。
它包含兩個參數(shù)。
parallelismThreshold -它指定在映射中并行執(zhí)行多少個元素操作之后。
transformer -這將在將數(shù)據(jù)傳遞到指定函數(shù)之前轉(zhuǎn)換數(shù)據(jù)。
例如,
import java.util.concurrent.ConcurrentHashMap; class Main { public static void main(String[] args) { ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>(); numbers.put("One", 1); numbers.put("Two", 2); numbers.put("Three", 3); System.out.println("ConcurrentHashMap: " + numbers); //forEach()不包含傳遞的函數(shù) numbers.forEach(4, (k, v) -> System.out.println("key: " + k + " value: " + v)); // forEach()傳遞指定函數(shù) System.out.print("Values are "); numbers.forEach(4, (k, v) -> v, (v) -> System.out.print(v + ", ")); } }
輸出結(jié)果
ConcurrentHashMap: {One = 1, Two = 2, Three = 3} key: One value: 1 key: Two value: 2 key: Three value: 3 Values are 1, 2, 3,
在上面的程序中,我們使用了并行閾值4。這意味著,如果映射包含4個條目,則該操作將并行執(zhí)行。
forEach()方法的變體
forEachEntry() - 為每個條目執(zhí)行指定的函數(shù)
forEachKey() - 為每個鍵執(zhí)行指定的函數(shù)
forEachValue() - 為每個值執(zhí)行指定的函數(shù)
search()方法基于指定的函數(shù)搜索map并返回匹配的條目。
這里,指定的函數(shù)決定搜索什么條目。
它還包含一個可選參數(shù)parallelThreshold。并行閾值指定在映射中有多少元素之后并行執(zhí)行操作。
例如,
import java.util.concurrent.ConcurrentHashMap; class Main { public static void main(String[] args) { ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>(); numbers.put("One", 1); numbers.put("Two", 2); numbers.put("Three", 3); System.out.println("ConcurrentHashMap: " + numbers); // 使用 search() String key = numbers.search(4, (k, v) -> {return v == 3 ? k: null;}); System.out.println("被搜索的值: " + key); } }
輸出結(jié)果
ConcurrentHashMap: {One=1, Two=2, Three=3} 被搜索的值: Three
search()方法的變體
searchEntries() - 搜索函數(shù)應(yīng)用于鍵/值映射
searchKeys() - 搜索函數(shù)僅適用于按鍵
searchValues() - 搜索函數(shù)僅應(yīng)用于值
reduce()方法累積(聚集)映射中的每個條目。 當(dāng)我們需要所有條目來執(zhí)行一項(xiàng)常見任務(wù)(例如添加映射的所有值)時,可以使用此方法。
它包含兩個參數(shù)。
parallelismThreshold -它指定在有多少元素之后,map中的操作將并行執(zhí)行。
transformer - 這將在數(shù)據(jù)傳遞給指定函數(shù)之前對數(shù)據(jù)進(jìn)行轉(zhuǎn)換。
例如,
import java.util.concurrent.ConcurrentHashMap; class Main { public static void main(String[] args) { ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>(); numbers.put("One", 1); numbers.put("Two", 2); numbers.put("Three", 3); System.out.println("ConcurrentHashMap: " + numbers); // 使用 search() int sum = numbers.reduce(4, (k, v) -> v, (v1, v2) -> v1 + v2); System.out.println("所有值的總和: " + sum); } }
輸出結(jié)果
ConcurrentHashMap: {One=1, Two=2, Three=3} 所有值的總和: 6
在上面的程序中,請注意以下語句
numbers.reduce(4, (k, v) -> v, (v1, v2) -> v1+v2);
這里,
4 是并行閾值
(k, v) -> v是一個轉(zhuǎn)換函數(shù)。它將鍵/值映射僅轉(zhuǎn)換為值。
(v1, v2) -> v1+v2 是計(jì)算大小函數(shù)。它收集所有值并將所有值相加。
reduce()方法的變體
reduceEntries() - 返回使用指定的reducer函數(shù)收集所有條目的結(jié)果
reduceKeys() - 返回使用指定的reducer函數(shù)收集所有鍵的結(jié)果
reduceValues() - 返回使用指定的reducer函數(shù)收集所有值的結(jié)果
以下是ConcurrentHashMap和HashMap之間的一些區(qū)別,
ConcurrentHashMap是線程安全的集合。也就是說,多個線程可以同時訪問和修改它。
ConcurrentHashMap提供用于批量操作的方法,例如forEach(),search()和reduce()。
ConcurrentHashMap類允許多個線程修改操作并發(fā)進(jìn)行。
默認(rèn)情況下,并發(fā)哈希映射分為16段。這就是為什么允許16個線程同時修改映射的原因。但是,一次可以訪問任意數(shù)量的線程。
如果指定的鍵已經(jīng)存在,則putIfAbsent()方法將不會覆蓋映射中的條目。