---
title: Javaéå常è§é¢è¯é¢æ»ç»
description: ç³»ç»æ¢³çJavaéåæ¡æ¶å¸¸è§ç¥è¯ç¹ä¸é«é¢é¢è¯é¢ï¼è¦çListãSetãQueueãMapåå
¶å
¸åå®ç°å¦ArrayListãLinkedListãHashSetãHashMapãConcurrentHashMapãBlockingQueueçï¼å¹¶ç»åæºç 讲解æ©å®¹æºå¶ãæ¶é´å¤æåº¦ã线ç¨å®å
¨ä¸fail-fast/fail-safeçå
³é®ç»èã
category: Java
tag:
- Javaéå
head:
- - meta
- name: keywords
content: Javaéåé¢è¯é¢,Collection,List,ArrayList,LinkedList,Set,HashSet,TreeSet,Queue,Deque,ArrayDeque,PriorityQueue,BlockingQueue,HashMap,TreeMap,ConcurrentHashMap,Hashtable,fail-fast,fail-safe,æ©å®¹æºå¶
---
è¿é¨åå
容æèª [JavaGuide](https://javaguide.cn/) ä¸é¢å ç¯æç« ä¸çéç¹ï¼
- [Java éå常è§é¢è¯é¢æ»ç»ï¼ä¸ï¼](https://javaguide.cn/java/collection/java-collection-questions-01.html)ï¼Java éååºç¡ã`ArrayList`ã`LinkedList`ã`HashSet`ã`ArrayDeque`ã`PriorityQueue`ã`BlockingQueue` çï¼
- [Java éå常è§é¢è¯é¢æ»ç»ï¼ä¸ï¼](https://javaguide.cn/java/collection/java-collection-questions-02.html)ï¼ `HashMap`ã`ConcurrentHashMap` çï¼
## åºç¡æ¦å¿µ
### ç®åä»ç»ä¸ä¸ Java éå
Java éåï¼ä¹å«ä½å®¹å¨ï¼ä¸»è¦æ¯ç±ä¸¤å¤§æ¥å£æ´¾çèæ¥ï¼ä¸ä¸ªæ¯ `Collection`æ¥å£ï¼ä¸»è¦ç¨äºåæ¾åä¸å
ç´ ï¼å¦ä¸ä¸ªæ¯ `Map` æ¥å£ï¼ä¸»è¦ç¨äºåæ¾é®å¼å¯¹ã对äº`Collection` æ¥å£ï¼ä¸é¢åæä¸ä¸ªä¸»è¦ç忥å£ï¼`List`ã`Set` ã `Queue`ã
Java éåæ¡æ¶å¦ä¸å¾æç¤ºï¼

注ï¼å¾ä¸åªå举äºä¸»è¦çç»§æ¿æ´¾çå
³ç³»ï¼å¹¶æ²¡æå举ææå
³ç³»ãæ¯æ¹çç¥äº`AbstractList`, `NavigableSet`çæ½è±¡ç±»ä»¥åå
¶ä»çä¸äºè¾
å©ç±»ï¼å¦æ³æ·±å
¥äºè§£ï¼å¯èªè¡æ¥çæºç ã
### 说说 List, Set, Queue, Map åè
çåºå«ï¼
- `List`(对ä»é¡ºåºç好帮æ): åå¨çå
ç´ æ¯æåºçãå¯éå¤çã
- `Set`(注éç¬ä¸æ äºçæ§è´¨): åå¨çå
ç´ ä¸å¯éå¤çã
- `Queue`(å®ç°æéåè½çå«å·æº): æç¹å®çæéè§åæ¥ç¡®å®å
å顺åºï¼åå¨çå
ç´ æ¯æåºçãå¯éå¤çã
- `Map`(ç¨ key æ¥æç´¢çä¸å®¶): 使ç¨é®å¼å¯¹ï¼key-valueï¼åå¨ï¼ç±»ä¼¼äºæ°å¦ä¸ç彿° y=f(x)ï¼"x" 代表 keyï¼"y" 代表 valueï¼key æ¯æ åºçãä¸å¯éå¤çï¼value æ¯æ åºçãå¯éå¤çï¼æ¯ä¸ªé®æå¤æ å°å°ä¸ä¸ªå¼ã
## List
### âï¸ArrayList å Arrayï¼æ°ç»ï¼çåºå«ï¼
`ArrayList` å
é¨åºäºå¨ææ°ç»å®ç°ï¼æ¯ `Array`ï¼éææ°ç»ï¼ 使ç¨èµ·æ¥æ´å çµæ´»ï¼
- `ArrayList`伿 ¹æ®å®é
åå¨çå
ç´ å¨æå°æ©å®¹æç¼©å®¹ï¼è `Array` 被å建ä¹åå°±ä¸è½æ¹åå®çé¿åº¦äºã
- `ArrayList` å
è®¸ä½ ä½¿ç¨æ³åæ¥ç¡®ä¿ç±»åå®å
¨ï¼`Array` åä¸å¯ä»¥ã
- `ArrayList` ä¸åªè½åå¨å¯¹è±¡ã对äºåºæ¬ç±»åæ°æ®ï¼éè¦ä½¿ç¨å
¶å¯¹åºçå
è£
ç±»ï¼å¦ IntegerãDouble çï¼ã`Array` å¯ä»¥ç´æ¥åå¨åºæ¬ç±»åæ°æ®ï¼ä¹å¯ä»¥åå¨å¯¹è±¡ã
- `ArrayList` æ¯ææå
¥ãå é¤ãéåçå¸¸è§æä½ï¼å¹¶ä¸æä¾äºä¸°å¯ç API æä½æ¹æ³ï¼æ¯å¦ `add()`ã`remove()`çã`Array` åªæ¯ä¸ä¸ªåºå®é¿åº¦çæ°ç»ï¼åªè½æç
§ä¸æ 访é®å
¶ä¸çå
ç´ ï¼ä¸å
·å¤å¨ææ·»å ãå é¤å
ç´ çè½åã
- `ArrayList`å建æ¶ä¸éè¦æå®å¤§å°ï¼è`Array`å建æ¶å¿
é¡»æå®å¤§å°ã
ä¸é¢æ¯äºè
使ç¨çç®å对æ¯ï¼
`Array`ï¼
```java
// åå§åä¸ä¸ª String ç±»åçæ°ç»
String[] stringArr = new String[]{"hello", "world", "!"};
// ä¿®æ¹æ°ç»å
ç´ çå¼
stringArr[0] = "goodbye";
System.out.println(Arrays.toString(stringArr));// [goodbye, world, !]
// å 餿°ç»ä¸çå
ç´ ï¼éè¦æå¨ç§»å¨åé¢çå
ç´
for (int i = 0; i < stringArr.length - 1; i++) {
stringArr[i] = stringArr[i + 1];
}
stringArr[stringArr.length - 1] = null;
System.out.println(Arrays.toString(stringArr));// [world, !, null]
```
`ArrayList` ï¼
```java
// åå§åä¸ä¸ª String ç±»åç ArrayList
ArrayList stringList = new ArrayList<>(Arrays.asList("hello", "world", "!"));
// æ·»å å
ç´ å° ArrayList ä¸
stringList.add("goodbye");
System.out.println(stringList);// [hello, world, !, goodbye]
// ä¿®æ¹ ArrayList ä¸çå
ç´
stringList.set(0, "hi");
System.out.println(stringList);// [hi, world, !, goodbye]
// å é¤ ArrayList ä¸çå
ç´
stringList.remove(0);
System.out.println(stringList); // [world, !, goodbye]
```
### ArrayList å¯ä»¥æ·»å null å¼åï¼
`ArrayList` ä¸å¯ä»¥åå¨ä»»ä½ç±»åç对象ï¼å
æ¬ `null` å¼ãä¸è¿ï¼ä¸å»ºè®®å`ArrayList` 䏿·»å `null` å¼ï¼ `null` 弿 æä¹ï¼ä¼è®©ä»£ç é¾ä»¥ç»´æ¤æ¯å¦å¿è®°åå¤ç©ºå¤çå°±ä¼å¯¼è´ç©ºæéå¼å¸¸ã
示ä¾ä»£ç ï¼
```java
ArrayList listOfStrings = new ArrayList<>();
listOfStrings.add(null);
listOfStrings.add("java");
System.out.println(listOfStrings);
```
è¾åºï¼
```
[null, java]
```
### âï¸ArrayList æå
¥åå é¤å
ç´ çæ¶é´å¤æåº¦ï¼
å¯¹äºæå
¥ï¼
- 头鍿å
¥ï¼ç±äºéè¦å°ææå
ç´ é½ä¾æ¬¡ååç§»å¨ä¸ä¸ªä½ç½®ï¼å æ¤æ¶é´å¤æåº¦æ¯ O(n)ã
- 尾鍿å
¥ï¼å½ `ArrayList` çå®¹éæªè¾¾å°æéæ¶ï¼å¾å表æ«å°¾æå
¥å
ç´ çæ¶é´å¤æåº¦æ¯ O(1)ï¼å 为å®åªéè¦å¨æ°ç»æ«å°¾æ·»å ä¸ä¸ªå
ç´ å³å¯ï¼å½å®¹éå·²è¾¾å°æéå¹¶ä¸éè¦æ©å®¹æ¶ï¼åéè¦æ§è¡ä¸æ¬¡ O(n) çæä½å°åæ°ç»å¤å¶å°æ°çæ´å¤§çæ°ç»ä¸ï¼ç¶ååæ§è¡ O(1) çæä½æ·»å å
ç´ ã
- æå®ä½ç½®æå
¥ï¼éè¦å°ç®æ ä½ç½®ä¹åçææå
ç´ é½ååç§»å¨ä¸ä¸ªä½ç½®ï¼ç¶ååææ°å
ç´ æ¾å
¥æå®ä½ç½®ãè¿ä¸ªè¿ç¨éè¦ç§»å¨å¹³å n/2 个å
ç´ ï¼å æ¤æ¶é´å¤æåº¦ä¸º O(n)ã
对äºå é¤ï¼
- 头é¨å é¤ï¼ç±äºéè¦å°ææå
ç´ ä¾æ¬¡ååç§»å¨ä¸ä¸ªä½ç½®ï¼å æ¤æ¶é´å¤æåº¦æ¯ O(n)ã
- å°¾é¨å é¤ï¼å½å é¤çå
ç´ ä½äºå表æ«å°¾æ¶ï¼æ¶é´å¤æåº¦ä¸º O(1)ã
- æå®ä½ç½®å é¤ï¼éè¦å°ç®æ å
ç´ ä¹åçææå
ç´ ååç§»å¨ä¸ä¸ªä½ç½®ä»¥å¡«è¡¥è¢«å é¤ç空ç½ä½ç½®ï¼å æ¤éè¦ç§»å¨å¹³å n/2 个å
ç´ ï¼æ¶é´å¤æåº¦ä¸º O(n)ã
è¿éç®åå举ä¸ä¸ªä¾åï¼
```
// ArrayListçåºå±æ°ç»å¤§å°ä¸º10ï¼æ¤æ¶åå¨äº7个å
ç´
+---+---+---+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | | | |
+---+---+---+---+---+---+---+---+---+---+
0 1 2 3 4 5 6 7 8 9
// å¨ç´¢å¼ä¸º1çä½ç½®æå
¥ä¸ä¸ªå
ç´ 8ï¼è¯¥å
ç´ åé¢çææå
ç´ é½è¦åå³ç§»å¨ä¸ä½
+---+---+---+---+---+---+---+---+---+---+
| 1 | 8 | 2 | 3 | 4 | 5 | 6 | 7 | | |
+---+---+---+---+---+---+---+---+---+---+
0 1 2 3 4 5 6 7 8 9
// å é¤ç´¢å¼ä¸º1çä½ç½®çå
ç´ ï¼è¯¥å
ç´ åé¢çææå
ç´ é½è¦å左移å¨ä¸ä½
+---+---+---+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | | | |
+---+---+---+---+---+---+---+---+---+---+
0 1 2 3 4 5 6 7 8 9
```
### âï¸LinkedList æå
¥åå é¤å
ç´ çæ¶é´å¤æåº¦ï¼
- 头鍿å
¥/å é¤ï¼åªéè¦ä¿®æ¹å¤´ç»ç¹çæéå³å¯å®ææå
¥/å 餿ä½ï¼å æ¤æ¶é´å¤æåº¦ä¸º O(1)ã
- 尾鍿å
¥/å é¤ï¼åªéè¦ä¿®æ¹å°¾ç»ç¹çæéå³å¯å®ææå
¥/å 餿ä½ï¼å æ¤æ¶é´å¤æåº¦ä¸º O(1)ã
- æå®ä½ç½®æå
¥/å é¤ï¼éè¦å
ç§»å¨å°æå®ä½ç½®ï¼åä¿®æ¹æå®èç¹çæé宿æå
¥/å é¤ï¼ä¸è¿ç±äºæå¤´å°¾æéï¼å¯ä»¥ä»è¾è¿çæéåºåï¼å æ¤éè¦éåå¹³å n/4 个å
ç´ ï¼æ¶é´å¤æåº¦ä¸º O(n)ã
è¿éç®åå举ä¸ä¸ªä¾åï¼å妿们è¦å é¤èç¹ 9 çè¯ï¼éè¦å
éåé¾è¡¨æ¾å°è¯¥èç¹ãç¶åï¼åæ§è¡ç¸åºèç¹æéæåçæ´æ¹ï¼å
·ä½çæºç å¯ä»¥åèï¼[LinkedList æºç åæ](https://javaguide.cn/java/collection/linkedlist-source-code.html) ã

### LinkedList 为ä»ä¹ä¸è½å®ç° RandomAccess æ¥å£ï¼
`RandomAccess` æ¯ä¸ä¸ªæ è®°æ¥å£ï¼ç¨æ¥è¡¨æå®ç°è¯¥æ¥å£çç±»æ¯æéæºè®¿é®ï¼å³å¯ä»¥éè¿ç´¢å¼å¿«é访é®å
ç´ ï¼ãç±äº `LinkedList` åºå±æ°æ®ç»ææ¯é¾è¡¨ï¼å
åå°åä¸è¿ç»ï¼åªè½éè¿æéæ¥å®ä½ï¼ä¸æ¯æéæºå¿«é访é®ï¼æä»¥ä¸è½å®ç° `RandomAccess` æ¥å£ã
### ArrayList ä¸ LinkedList åºå«?
- **æ¯å¦ä¿è¯çº¿ç¨å®å
¨ï¼** `ArrayList` å `LinkedList` 齿¯ä¸åæ¥çï¼ä¹å°±æ¯ä¸ä¿è¯çº¿ç¨å®å
¨ï¼
- **åºå±æ°æ®ç»æï¼** `ArrayList` åºå±ä½¿ç¨çæ¯ **`Object` æ°ç»**ï¼`LinkedList` åºå±ä½¿ç¨çæ¯ **ååé¾è¡¨** æ°æ®ç»æï¼JDK1.6 ä¹å为循ç¯é¾è¡¨ï¼JDK1.7 åæ¶äºå¾ªç¯ã注æååé¾è¡¨ååå循ç¯é¾è¡¨çåºå«ï¼ä¸é¢æä»ç»å°ï¼ï¼
- **æå
¥åå 餿¯å¦åå
ç´ ä½ç½®çå½±åï¼**
- `ArrayList` éç¨æ°ç»åå¨ï¼æä»¥æå
¥åå é¤å
ç´ çæ¶é´å¤æåº¦åå
ç´ ä½ç½®çå½±åã æ¯å¦ï¼æ§è¡`add(E e)`æ¹æ³çæ¶åï¼ `ArrayList` ä¼é»è®¤å¨å°æå®çå
ç´ è¿½å å°æ¤åè¡¨çæ«å°¾ï¼è¿ç§æ
嵿¶é´å¤æåº¦å°±æ¯ O(1)ã使¯å¦æè¦å¨æå®ä½ç½® i æå
¥åå é¤å
ç´ çè¯ï¼`add(int index, E element)`ï¼ï¼æ¶é´å¤æåº¦å°±ä¸º O(n)ãå 为å¨è¿è¡ä¸è¿°æä½çæ¶åéåä¸ç¬¬ i å第 i 个å
ç´ ä¹åç(n-i)个å
ç´ é½è¦æ§è¡ååä½/ååç§»ä¸ä½çæä½ã
- `LinkedList` éç¨é¾è¡¨åå¨ï¼æä»¥å¨å¤´å°¾æå
¥æè
å é¤å
ç´ ä¸åå
ç´ ä½ç½®çå½±åï¼`add(E e)`ã`addFirst(E e)`ã`addLast(E e)`ã`removeFirst()`ã `removeLast()`ï¼ï¼æ¶é´å¤æåº¦ä¸º O(1)ï¼å¦ææ¯è¦å¨æå®ä½ç½® `i` æå
¥åå é¤å
ç´ çè¯ï¼`add(int index, E element)`ï¼`remove(Object o)`,`remove(int index)`ï¼ï¼ æ¶é´å¤æåº¦ä¸º O(n) ï¼å 为éè¦å
ç§»å¨å°æå®ä½ç½®åæå
¥åå é¤ã
- **æ¯å¦æ¯æå¿«ééæºè®¿é®ï¼** `LinkedList` 䏿¯æé«æçéæºå
ç´ è®¿é®ï¼è `ArrayList`ï¼å®ç°äº `RandomAccess` æ¥å£ï¼ æ¯æãå¿«ééæºè®¿é®å°±æ¯éè¿å
ç´ çåºå·å¿«éè·åå
ç´ å¯¹è±¡(对åºäº`get(int index)`æ¹æ³)ã
- **å
å空é´å ç¨ï¼** `ArrayList` çç©ºé´æµªè´¹ä¸»è¦ä½ç°å¨å¨ list å表çç»å°¾ä¼é¢çä¸å®ç容é空é´ï¼è LinkedList ç空é´è±è´¹åä½ç°å¨å®çæ¯ä¸ä¸ªå
ç´ é½éè¦æ¶èæ¯ ArrayList æ´å¤ç空é´ï¼å 为è¦åæ¾ç´æ¥åç»§åç´æ¥å驱以忰æ®ï¼ã
æä»¬å¨é¡¹ç®ä¸ä¸è¬æ¯ä¸ä¼ä½¿ç¨å° `LinkedList` çï¼éè¦ç¨å° `LinkedList` çåºæ¯å ä¹é½å¯ä»¥ä½¿ç¨ `ArrayList` æ¥ä»£æ¿ï¼å¹¶ä¸ï¼æ§è½é叏伿´å¥½ï¼å°±è¿ `LinkedList` çä½è
çº¦ä¹¦äº Â· 叿´å
ï¼Josh Blochï¼èªå·±é½è¯´ä»æ¥ä¸ä¼ä½¿ç¨ `LinkedList` ã

å¦å¤ï¼ä¸è¦ä¸æè¯å°è®¤ä¸º `LinkedList` ä½ä¸ºé¾è¡¨å°±æéåå
ç´ å¢å çåºæ¯ãæå¨ä¸é¢ä¹è¯´äºï¼`LinkedList` ä»
ä»
å¨å¤´å°¾æå
¥æè
å é¤å
ç´ çæ¶åæ¶é´å¤æåº¦è¿ä¼¼ O(1)ï¼å
¶ä»æ
åµå¢å å
ç´ ç平忶é´å¤æåº¦é½æ¯ O(n) ã
#### è¡¥å
å
容: ååé¾è¡¨ååå循ç¯é¾è¡¨
**ååé¾è¡¨ï¼** å
å«ä¸¤ä¸ªæéï¼ä¸ä¸ª prev æååä¸ä¸ªèç¹ï¼ä¸ä¸ª next æååä¸ä¸ªèç¹ã

**åå循ç¯é¾è¡¨ï¼** æåä¸ä¸ªèç¹ç next æå headï¼è head ç prev æåæåä¸ä¸ªèç¹ï¼ææä¸ä¸ªç¯ã

#### è¡¥å
å
容:RandomAccess æ¥å£
```java
public interface RandomAccess {
}
```
æ¥çæºç æä»¬åç°å®é
ä¸ `RandomAccess` æ¥å£ä¸ä»ä¹é½æ²¡æå®ä¹ãæä»¥ï¼å¨æçæ¥ `RandomAccess` æ¥å£ä¸è¿æ¯ä¸ä¸ªæ è¯ç½¢äºãæ è¯ä»ä¹ï¼ æ è¯å®ç°è¿ä¸ªæ¥å£çç±»å
·æéæºè®¿é®åè½ã
å¨ `binarySearch()` æ¹æ³ä¸ï¼å®è¦å¤æä¼ å
¥ç list æ¯å¦ `RandomAccess` çå®ä¾ï¼å¦ææ¯ï¼è°ç¨`indexedBinarySearch()`æ¹æ³ï¼å¦æä¸æ¯ï¼é£ä¹è°ç¨`iteratorBinarySearch()`æ¹æ³
```java
public static
int binarySearch(List extends Comparable super T>> list, T key) {
if (list instanceof RandomAccess || list.size() Fail-fast systems are designed to immediately stop functioning upon encountering an unexpected condition. This immediate failure helps to catch errors early, making debugging more straightforward.
å¿«éå¤±è´¥çææ³å³é对å¯è½åççå¼å¸¸è¿è¡æå表ææ
é并忢è¿è¡ï¼éè¿å°½æ©çåç°å忢é误ï¼é使
éç³»ç»çº§èçé£é©ã
å¨`java.util`å
ä¸ç大é¨åé忝䏿¯æçº¿ç¨å®å
¨çï¼ä¸ºäºè½å¤æååç°å¹¶åæä½å¯¼è´çº¿ç¨å®å
¨é£é©ï¼æåºéè¿ç»´æ¤ä¸ä¸ª`modCount`è®°å½ä¿®æ¹ç次æ°ï¼è¿ä»£æé´éè¿æ¯å¯¹é¢æä¿®æ¹æ¬¡æ°`expectedModCount`å`modCount`æ¯å¦ä¸è´æ¥å¤ææ¯å¦åå¨å¹¶åæä½ï¼ä»èå®ç°å¿«é失败ï¼ç±æ¤ä¿è¯å¨é¿å
å¨å¼å¸¸æ¶æ§è¡éå¿
è¦ç夿代ç ã
对åºçæä»¬ç»åºä¸é¢è¿æ ·ä¸æ®µå¨ç¤ºä¾ï¼æä»¬é¦å
æå
¥`100`个æä½å
ç´ ï¼ä¸ä¸ªçº¿ç¨è¿ä»£å
ç´ ï¼ä¸ä¸ªçº¿ç¨å é¤å
ç´ ï¼æç»è¾åºç»æå¦æ¿æåº`ConcurrentModificationException`ï¼
```java
// 使ç¨çº¿ç¨å®å
¨ç CopyOnWriteArrayList é¿å
ConcurrentModificationException
List list = new CopyOnWriteArrayList<>();
CountDownLatch countDownLatch = new CountDownLatch(2);
// æ·»å å
ç´
for (int i = 0; i < 100; i++) {
list.add(i);
}
Thread t1 = new Thread(() -> {
// è¿ä»£å
ç´ (注æï¼Integer æ¯ä¸å¯åçï¼è¿éç i++ ä¸ä¼ä¿®æ¹ list ä¸çå¼)
for (Integer i : list) {
i++; // è¿è¡ä»£ç å®é
䏿²¡æä¿®æ¹listä¸çå
ç´
}
countDownLatch.countDown();
});
Thread t2 = new Thread(() -> {
System.out.println("å é¤å
ç´ 1");
list.remove(Integer.valueOf(1)); // ä½¿ç¨ Integer.valueOf(1) å 餿å®å¼ç对象
countDownLatch.countDown();
});
t1.start();
t2.start();
countDownLatch.await();
```
æä»¬å¨åå§åæ¶æå
¥äº`100`个å
ç´ ï¼æ¤æ¶å¯¹åºçä¿®æ¹`modCount`次æ°ä¸º`100`ï¼éåçº¿ç¨ 2 å¨çº¿ç¨ 1 è¿ä»£æé´è¿è¡å
ç´ å 餿ä½ï¼æ¤æ¶å¯¹åºç`modCount`å°±å为`101`ã çº¿ç¨ 1 å¨éå`foreach`第 2 轮循ç¯åç°`modCount` 为`101`ï¼ä¸é¢æç`expectedModCount(å¼ä¸º100å 为åå§åæå
¥äºå
ç´ 100个)`ä¸çï¼å¤å®ä¸ºå¹¶åæä½å¼å¸¸ï¼äºæ¯ä¾¿å¿«éå¤±è´¥ï¼æåº`ConcurrentModificationException`ï¼

å¯¹æ¤æä»¬ä¹ç»åº`for`循ç¯åºå±è¿ä»£å¨è·åä¸ä¸ä¸ªå
ç´ æ¶ç`next`æ¹æ³ï¼å¯ä»¥çå°å
¶å
é¨ç`checkForComodification`å
·æéå¯¹ä¿®æ¹æ¬¡æ°æ¯å¯¹çé»è¾ï¼
```java
public E next() {
//æ£æ¥æ¯å¦åå¨å¹¶åä¿®æ¹
checkForComodification();
//......
//è¿åä¸ä¸ä¸ªå
ç´
return (E) elementData[lastRet = i];
}
final void checkForComodification() {
//å½å循ç¯é忬¡æ°åé¢æä¿®æ¹æ¬¡æ°ä¸ä¸è´æ¶ï¼å°±ä¼æåºConcurrentModificationException
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
```
è`fail-safe`ä¹å°±æ¯å®å
¨å¤±è´¥çå«ä¹ï¼å®æ¨å¨å³ä½¿é¢å¯¹æå¤æ
åµä¹è½æ¢å¤å¹¶ç»§ç»è¿è¡ï¼è¿ä½¿å¾å®ç¹å«éç¨äºä¸ç¡®å®æè
ä¸ç¨³å®çç¯å¢ï¼
> Fail-safe systems take a different approach, aiming to recover and continue even in the face of unexpected conditions. This makes them particularly suited for uncertain or volatile environments.
è¯¥ææ³å¸¸è¿ç¨äºå¹¶å容å¨ï¼æç»å
¸çå®ç°å°±æ¯`CopyOnWriteArrayList`çå®ç°ï¼éè¿åæ¶å¤å¶çææ³ä¿è¯å¨è¿è¡ä¿®æ¹æä½æ¶å¤å¶åºä¸ä»½å¿«ç
§ï¼åºäºè¿ä»½å¿«ç
§å®ææ·»å æè
å 餿ä½åï¼å°`CopyOnWriteArrayList`åºå±çæ°ç»å¼ç¨æåè¿ä¸ªæ°çæ°ç»ç©ºé´ï¼ç±æ¤é¿å
è¿ä»£æ¶è¢«å¹¶åä¿®æ¹æå¹²æ°æå¯¼è´å¹¶åæä½å®å
¨é®é¢ï¼å½ç¶è¿ç§åæ³ä¹åå¨ç¼ºç¹ï¼å³è¿è¡éåæä½æ¶æ æ³è·å¾å®æ¶ç»æï¼

å¯¹åºæä»¬ä¹ç»åº`CopyOnWriteArrayList`å®ç°`fail-safe`çæ ¸å¿ä»£ç ï¼å¯ä»¥çå°å®çå®ç°å°±æ¯éè¿`getArray`è·åæ°ç»å¼ç¨ç¶åéè¿`Arrays.copyOf`å¾å°ä¸ä¸ªæ°ç»çå¿«ç
§ï¼åºäºè¿ä¸ªå¿«ç
§å®ææ·»å æä½åï¼ä¿®æ¹åºå±`array`åéæåçå¼ç¨å°åç±æ¤å®æåæ¶å¤å¶ï¼
```java
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//è·ååææ°ç»
Object[] elements = getArray();
int len = elements.length;
//åºäºåææ°ç»å¤å¶åºä¸ä»½å
åå¿«ç
§
Object[] newElements = Arrays.copyOf(elements, len + 1);
//è¿è¡æ·»å æä½
newElements[len] = e;
//arrayæåæ°çæ°ç»
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
```
## Set
### Comparable å Comparator çåºå«
`Comparable` æ¥å£å `Comparator` æ¥å£é½æ¯ Java ä¸ç¨äºæåºçæ¥å£ï¼å®ä»¬å¨å®ç°ç±»å¯¹è±¡ä¹é´æ¯è¾å¤§å°ãæåºçæ¹é¢åæ¥äºéè¦ä½ç¨ï¼
- `Comparable` æ¥å£å®é
䏿¯åºèª`java.lang`å
宿ä¸ä¸ª `compareTo(Object obj)`æ¹æ³ç¨æ¥æåº
- `Comparator`æ¥å£å®é
䏿¯åºèª `java.util` å
宿ä¸ä¸ª`compare(Object obj1, Object obj2)`æ¹æ³ç¨æ¥æåº
ä¸è¬æä»¬éè¦å¯¹ä¸ä¸ªéå使ç¨èªå®ä¹æåºæ¶ï¼æä»¬å°±è¦éå`compareTo()`æ¹æ³æ`compare()`æ¹æ³ï¼å½æä»¬éè¦å¯¹æä¸ä¸ªéåå®ç°ä¸¤ç§æåºæ¹å¼ï¼æ¯å¦ä¸ä¸ª `song` 对象ä¸çæååææååå«éç¨ä¸ç§æåºæ¹æ³çè¯ï¼æä»¬å¯ä»¥éå`compareTo()`æ¹æ³å使ç¨èªå¶ç`Comparator`æ¹æ³æè
以两个 `Comparator` æ¥å®ç°æåæåºåææåæåºï¼ç¬¬äºç§ä»£è¡¨æä»¬åªè½ä½¿ç¨ä¸¤ä¸ªåæ°çç `Collections.sort()`.
#### Comparator å®å¶æåº
```java
ArrayList arrayList = new ArrayList();
arrayList.add(-1);
arrayList.add(3);
arrayList.add(3);
arrayList.add(-5);
arrayList.add(7);
arrayList.add(4);
arrayList.add(-9);
arrayList.add(-7);
System.out.println("åå§æ°ç»:");
System.out.println(arrayList);
// void reverse(List list)ï¼å转
Collections.reverse(arrayList);
System.out.println("Collections.reverse(arrayList):");
System.out.println(arrayList);
// void sort(List list),æèªç¶æåºçååºæåº
Collections.sort(arrayList);
System.out.println("Collections.sort(arrayList):");
System.out.println(arrayList);
// å®å¶æåºçç¨æ³
Collections.sort(arrayList, new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
System.out.println("å®å¶æåºåï¼");
System.out.println(arrayList);
```
Output:
```
åå§æ°ç»:
[-1, 3, 3, -5, 7, 4, -9, -7]
Collections.reverse(arrayList):
[-7, -9, 4, 7, -5, 3, 3, -1]
Collections.sort(arrayList):
[-9, -7, -5, -1, 3, 3, 4, 7]
å®å¶æåºåï¼
[7, 4, 3, 3, -1, -5, -7, -9]
```
#### éå compareTo æ¹æ³å®ç°æå¹´é¾æ¥æåº
```java
// person对象没æå®ç°Comparableæ¥å£ï¼æä»¥å¿
é¡»å®ç°ï¼è¿æ ·æä¸ä¼åºéï¼æå¯ä»¥ä½¿treemapä¸çæ°æ®æé¡ºåºæå
// åé¢ä¸ä¸ªä¾åçString类已ç»é»è®¤å®ç°äºComparableæ¥å£ï¼è¯¦ç»å¯ä»¥æ¥çStringç±»çAPIææ¡£ï¼å¦å¤å
¶ä»
// åIntegerç±»çé½å·²ç»å®ç°äºComparableæ¥å£ï¼æä»¥ä¸éè¦å¦å¤å®ç°äº
public class Person implements Comparable {
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/**
* TéåcompareToæ¹æ³å®ç°æå¹´é¾æ¥æåº
*/
@Override
public int compareTo(Person o) {
if (this.age > o.getAge()) {
return 1;
}
if (this.age < o.getAge()) {
return -1;
}
return 0;
}
}
public static void main(String[] args) {
TreeMap pdata = new TreeMap();
pdata.put(new Person("å¼ ä¸", 30), "zhangsan");
pdata.put(new Person("æå", 20), "lisi");
pdata.put(new Person("çäº", 10), "wangwu");
pdata.put(new Person("å°çº¢", 5), "xiaohong");
// å¾å°keyçå¼çåæ¶å¾å°keyæå¯¹åºçå¼
Set keys = pdata.keySet();
for (Person key : keys) {
System.out.println(key.getAge() + "-" + key.getName());
}
}
```
Outputï¼
```
5-å°çº¢
10-çäº
20-æå
30-å¼ ä¸
```
### æ¯è¾ HashSetãLinkedHashSet å TreeSet ä¸è
çå¼å
- `HashSet`ã`LinkedHashSet` å `TreeSet` 齿¯ `Set` æ¥å£çå®ç°ç±»ï¼é½è½ä¿è¯å
ç´ å¯ä¸ï¼å¹¶ä¸é½ä¸æ¯çº¿ç¨å®å
¨çã
- `HashSet`ã`LinkedHashSet` å `TreeSet` ç主è¦åºå«å¨äºåºå±æ°æ®ç»æä¸åã`HashSet` çåºå±æ°æ®ç»ææ¯åå¸è¡¨ï¼åºäº `HashMap` å®ç°ï¼ã`LinkedHashSet` çåºå±æ°æ®ç»ææ¯é¾è¡¨ååå¸è¡¨ï¼å
ç´ çæå
¥åååºé¡ºåºæ»¡è¶³ FIFOã`TreeSet` åºå±æ°æ®ç»ææ¯çº¢é»æ ï¼å
ç´ æ¯æåºçï¼æåºçæ¹å¼æèªç¶æåºåå®å¶æåºã
- åºå±æ°æ®ç»æä¸åå导è´è¿ä¸è
çåºç¨åºæ¯ä¸åã`HashSet` ç¨äºä¸éè¦ä¿è¯å
ç´ æå
¥åååºé¡ºåºçåºæ¯ï¼`LinkedHashSet` ç¨äºä¿è¯å
ç´ çæå
¥åååºé¡ºåºæ»¡è¶³ FIFO çåºæ¯ï¼`TreeSet` ç¨äºæ¯æå¯¹å
ç´ èªå®ä¹æåºè§åçåºæ¯ã
## Queue
### Queue ä¸ Deque çåºå«
`Queue` æ¯å端éåï¼åªè½ä»ä¸ç«¯æå
¥å
ç´ ï¼å¦ä¸ç«¯å é¤å
ç´ ï¼å®ç°ä¸ä¸è¬éµå¾ª **å
è¿å
åºï¼FIFOï¼** è§åã
`Queue` æ©å±äº `Collection` çæ¥å£ï¼æ ¹æ® **å 为容éé®é¢èå¯¼è´æä½å¤±è´¥åå¤çæ¹å¼çä¸å** å¯ä»¥åä¸ºä¸¤ç±»æ¹æ³: ä¸ç§å¨æä½å¤±è´¥å伿åºå¼å¸¸ï¼å¦ä¸ç§åä¼è¿åç¹æ®å¼ã
| `Queue` æ¥å£ | æåºå¼å¸¸ | è¿åç¹æ®å¼ |
| ------------ | --------- | ---------- |
| æå
¥éå°¾ | add(E e) | offer(E e) |
| å é¤éé¦ | remove() | poll() |
| æ¥è¯¢éé¦å
ç´ | element() | peek() |
`Deque` æ¯å端éåï¼å¨éåç两端åå¯ä»¥æå
¥æå é¤å
ç´ ã
`Deque` æ©å±äº `Queue` çæ¥å£, å¢å äºå¨éé¦åéå°¾è¿è¡æå
¥åå é¤çæ¹æ³ï¼åæ ·æ ¹æ®å¤±è´¥åå¤çæ¹å¼çä¸åå为两类ï¼
| `Deque` æ¥å£ | æåºå¼å¸¸ | è¿åç¹æ®å¼ |
| ------------ | ------------- | --------------- |
| æå
¥éé¦ | addFirst(E e) | offerFirst(E e) |
| æå
¥éå°¾ | addLast(E e) | offerLast(E e) |
| å é¤éé¦ | removeFirst() | pollFirst() |
| å é¤éå°¾ | removeLast() | pollLast() |
| æ¥è¯¢éé¦å
ç´ | getFirst() | peekFirst() |
| æ¥è¯¢éå°¾å
ç´ | getLast() | peekLast() |
äºå®ä¸ï¼`Deque` è¿æä¾æ `push()` å `pop()` çå
¶ä»æ¹æ³ï¼å¯ç¨äºæ¨¡ææ ã
### ArrayDeque ä¸ LinkedList çåºå«
`ArrayDeque` å `LinkedList` é½å®ç°äº `Deque` æ¥å£ï¼ä¸¤è
é½å
·æéåçåè½ï¼ä½ä¸¤è
æä»ä¹åºå«å¢ï¼
- `ArrayDeque` æ¯åºäºå¯åé¿çæ°ç»ååæéæ¥å®ç°ï¼è `LinkedList` åéè¿é¾è¡¨æ¥å®ç°ã
- `ArrayDeque` 䏿¯æåå¨ `NULL` æ°æ®ï¼ä½ `LinkedList` æ¯æã
- `ArrayDeque` æ¯å¨ JDK1.6 æè¢«å¼å
¥çï¼è`LinkedList` æ©å¨ JDK1.2 æ¶å°±å·²ç»åå¨ã
- `ArrayDeque` æå
¥æ¶å¯è½å卿©å®¹è¿ç¨, ä¸è¿åæåçæå
¥æä½ä¾ç¶ä¸º O(1)ãè½ç¶ `LinkedList` ä¸éè¦æ©å®¹ï¼ä½æ¯æ¯æ¬¡æå
¥æ°æ®æ¶åéè¦ç³è¯·æ°çå 空é´ï¼åææ§è½ç¸æ¯æ´æ
¢ã
仿§è½çè§åº¦ä¸ï¼éç¨ `ArrayDeque` æ¥å®ç°éåè¦æ¯ `LinkedList` æ´å¥½ãæ¤å¤ï¼`ArrayDeque` ä¹å¯ä»¥ç¨äºå®ç°æ ã
### 说ä¸è¯´ PriorityQueue
`PriorityQueue` æ¯å¨ JDK1.5 ä¸è¢«å¼å
¥ç, å
¶ä¸ `Queue` çåºå«å¨äºå
ç´ åºéé¡ºåºæ¯ä¸ä¼å
级ç¸å
³çï¼å³æ»æ¯ä¼å
级æé«çå
ç´ å
åºéã
è¿éå举å
¶ç¸å
³çä¸äºè¦ç¹ï¼
- `PriorityQueue` å©ç¨äºäºåå çæ°æ®ç»ææ¥å®ç°çï¼åºå±ä½¿ç¨å¯åé¿çæ°ç»æ¥å卿°æ®
- `PriorityQueue` éè¿å å
ç´ ç䏿µ®å䏿²ï¼å®ç°äºå¨ O(logn) çæ¶é´å¤æåº¦å
æå
¥å
ç´ åå é¤å é¡¶å
ç´ ã
- `PriorityQueue` æ¯é线ç¨å®å
¨çï¼ä¸ä¸æ¯æåå¨ `NULL` å `non-comparable` ç对象ã
- `PriorityQueue` é»è®¤æ¯å°é¡¶å ï¼ä½å¯ä»¥æ¥æ¶ä¸ä¸ª `Comparator` ä½ä¸ºæé åæ°ï¼ä»èæ¥èªå®ä¹å
ç´ ä¼å
级çå
åã
`PriorityQueue` å¨é¢è¯ä¸å¯è½æ´å¤çä¼åºç°å¨ææç®æ³çæ¶åï¼å
¸åä¾é¢å
æ¬å æåºãæ±ç¬¬ K å¤§çæ°ã带æå¾çéåçï¼æä»¥éè¦ä¼çç»ä½¿ç¨æè¡ã
### ä»ä¹æ¯ BlockingQueueï¼
`BlockingQueue` ï¼é»å¡éåï¼æ¯ä¸ä¸ªæ¥å£ï¼ç»§æ¿èª `Queue`ã`BlockingQueue`é»å¡çåå æ¯å
¶æ¯æå½éåæ²¡æå
ç´ æ¶ä¸ç´é»å¡ï¼ç´å°æå
ç´ ï¼è¿æ¯æå¦æéå已满ï¼ä¸ç´çå°éåå¯ä»¥æ¾å
¥æ°å
ç´ æ¶åæ¾å
¥ã
```java
public interface BlockingQueue extends Queue {
// ...
}
```
`BlockingQueue` 常ç¨äºç产è
-æ¶è´¹è
模åä¸ï¼ç产è
线ç¨ä¼åéå䏿·»å æ°æ®ï¼èæ¶è´¹è
线ç¨ä¼ä»éåä¸ååºæ°æ®è¿è¡å¤çã

### BlockingQueue çå®ç°ç±»æåªäºï¼

Java ä¸å¸¸ç¨çé»å¡éåå®ç°ç±»æä»¥ä¸å ç§ï¼
1. `ArrayBlockingQueue`ï¼ä½¿ç¨æ°ç»å®ç°çæçé»å¡éåãå¨å建æ¶éè¦æå®å®¹é大å°ï¼å¹¶æ¯æå
¬å¹³åéå
¬å¹³ä¸¤ç§æ¹å¼çéè®¿é®æºå¶ã
2. `LinkedBlockingQueue`ï¼ä½¿ç¨ååé¾è¡¨å®ç°çå¯éæçé»å¡éåãå¨å建æ¶å¯ä»¥æå®å®¹é大å°ï¼å¦æä¸æå®åé»è®¤ä¸º`Integer.MAX_VALUE`ãå`ArrayBlockingQueue`ä¸åçæ¯ï¼ å®ä»
æ¯æéå
¬å¹³çéè®¿é®æºå¶ã
3. `PriorityBlockingQueue`ï¼æ¯æä¼å
级æåºçæ çé»å¡éåãå
ç´ å¿
é¡»å®ç°`Comparable`æ¥å£æè
卿é 彿°ä¸ä¼ å
¥`Comparator`对象ï¼å¹¶ä¸ä¸è½æå
¥ null å
ç´ ã
4. `SynchronousQueue`ï¼åæ¥éåï¼æ¯ä¸ç§ä¸åå¨å
ç´ çé»å¡éåãæ¯ä¸ªæå
¥æä½é½å¿
é¡»çå¾
对åºçå 餿ä½ï¼åä¹å 餿ä½ä¹å¿
é¡»çå¾
æå
¥æä½ãå æ¤ï¼`SynchronousQueue`é常ç¨äºçº¿ç¨ä¹é´çç´æ¥ä¼ éæ°æ®ã
5. `DelayQueue`ï¼å»¶è¿éåï¼å
¶ä¸çå
ç´ åªæå°äºå
¶æå®çå»¶è¿æ¶é´ï¼æè½å¤ä»éåä¸åºéã
6. â¦â¦
æ¥å¸¸å¼åä¸ï¼è¿äºéå使ç¨çå
¶å®é½ä¸å¤ï¼äºè§£å³å¯ã
### âï¸ArrayBlockingQueue å LinkedBlockingQueue æä»ä¹åºå«ï¼
`ArrayBlockingQueue` å `LinkedBlockingQueue` æ¯ Java å¹¶åå
ä¸å¸¸ç¨ç两ç§é»å¡éåå®ç°ï¼å®ä»¬é½æ¯çº¿ç¨å®å
¨çãä¸è¿ï¼ä¸è¿å®ä»¬ä¹é´ä¹åå¨ä¸é¢è¿äºåºå«ï¼
- åºå±å®ç°ï¼`ArrayBlockingQueue` åºäºæ°ç»å®ç°ï¼è `LinkedBlockingQueue` åºäºé¾è¡¨å®ç°ã
- æ¯å¦æçï¼`ArrayBlockingQueue` æ¯æçéåï¼å¿
é¡»å¨åå»ºæ¶æå®å®¹é大å°ã`LinkedBlockingQueue` å建æ¶å¯ä»¥ä¸æå®å®¹é大å°ï¼é»è®¤æ¯`Integer.MAX_VALUE`ï¼ä¹å°±æ¯æ ççãä½ä¹å¯ä»¥æå®éå大å°ï¼ä»èæä¸ºæççã
- 鿝å¦åç¦»ï¼ `ArrayBlockingQueue`ä¸çéæ¯æ²¡æå离çï¼å³çäº§åæ¶è´¹ç¨çæ¯åä¸ä¸ªéï¼`LinkedBlockingQueue`ä¸ç鿝å离çï¼å³ç产ç¨çæ¯`putLock`ï¼æ¶è´¹æ¯`takeLock`ï¼è¿æ ·å¯ä»¥é²æ¢ç产è
åæ¶è´¹è
线ç¨ä¹é´çéäºå¤ºã
- å
åå ç¨ï¼`ArrayBlockingQueue` éè¦æååé
æ°ç»å
åï¼è `LinkedBlockingQueue` 忝卿åé
é¾è¡¨èç¹å
åãè¿æå³çï¼`ArrayBlockingQueue` å¨å建æ¶å°±ä¼å ç¨ä¸å®çå
å空é´ï¼ä¸å¾å¾ç³è¯·çå
忝å®é
æç¨çå
忴大ï¼è`LinkedBlockingQueue` åæ¯æ ¹æ®å
ç´ çå¢å è鿏å ç¨å
å空é´ã
## Mapï¼éè¦ï¼
### âï¸HashMap å Hashtable çåºå«
- **çº¿ç¨æ¯å¦å®å
¨ï¼** `HashMap` æ¯é线ç¨å®å
¨çï¼`Hashtable` æ¯çº¿ç¨å®å
¨ç,å 为 `Hashtable` å
é¨çæ¹æ³åºæ¬é½ç»è¿`synchronized` 修饰ãï¼å¦æä½ è¦ä¿è¯çº¿ç¨å®å
¨çè¯å°±ä½¿ç¨ `ConcurrentHashMap` å§ï¼ï¼ï¼
- **æçï¼** å 为线ç¨å®å
¨çé®é¢ï¼`HashMap` è¦æ¯ `Hashtable` æçé«ä¸ç¹ãå¦å¤ï¼`Hashtable` åºæ¬è¢«æ·æ±°ï¼ä¸è¦å¨ä»£ç ä¸ä½¿ç¨å®ï¼
- **对 Null key å Null value çæ¯æï¼** `HashMap` å¯ä»¥åå¨ null ç key å valueï¼ä½ null ä½ä¸ºé®åªè½æä¸ä¸ªï¼null ä½ä¸ºå¼å¯ä»¥æå¤ä¸ªï¼Hashtable ä¸å
许æ null é®å null å¼ï¼å¦åä¼æåº `NullPointerException`ã
- **åå§å®¹é大å°åæ¯æ¬¡æ©å
容é大å°çä¸åï¼** â å建æ¶å¦æä¸æå®å®¹éåå§å¼ï¼`Hashtable` é»è®¤çåå§å¤§å°ä¸º 11ï¼ä¹åæ¯æ¬¡æ©å
ï¼å®¹éåä¸ºåæ¥ç 2n+1ã`HashMap` é»è®¤çåå§å大å°ä¸º 16ãä¹åæ¯æ¬¡æ©å
ï¼å®¹éåä¸ºåæ¥ç 2 åãâ¡ å建æ¶å¦æç»å®äºå®¹éåå§å¼ï¼é£ä¹ `Hashtable` ä¼ç´æ¥ä½¿ç¨ä½ ç»å®ç大å°ï¼è `HashMap` ä¼å°å
¶æ©å
为 2 ç广¬¡æ¹å¤§å°ï¼`HashMap` ä¸ç`tableSizeFor()`æ¹æ³ä¿è¯ï¼ä¸é¢ç»åºäºæºä»£ç ï¼ãä¹å°±æ¯è¯´ `HashMap` æ»æ¯ä½¿ç¨ 2 çå¹ä½ä¸ºåå¸è¡¨ç大å°,åé¢ä¼ä»ç»å°ä¸ºä»ä¹æ¯ 2 ç广¬¡æ¹ã
- **åºå±æ°æ®ç»æï¼** JDK1.8 以åç `HashMap` å¨è§£å³åå¸å²çªæ¶æäºè¾å¤§çååï¼å½é¾è¡¨é¿åº¦å¤§äºéå¼ï¼é»è®¤ä¸º 8ï¼æ¶ï¼å°é¾è¡¨è½¬åä¸ºçº¢é»æ ï¼å°é¾è¡¨è½¬æ¢æçº¢é»æ åä¼å¤æï¼å¦æå½åæ°ç»çé¿åº¦å°äº 64ï¼é£ä¹ä¼éæ©å
è¿è¡æ°ç»æ©å®¹ï¼è䏿¯è½¬æ¢ä¸ºçº¢é»æ ï¼ï¼ä»¥åå°æç´¢æ¶é´ï¼åæä¸æä¼ç»åæºç 对è¿ä¸è¿ç¨è¿è¡åæï¼ã`Hashtable` 没æè¿æ ·çæºå¶ã
- **åå¸å½æ°çå®ç°**ï¼`HashMap` 对åå¸å¼è¿è¡äºé«ä½åä½ä½çæ··åæ°å¨å¤ç以åå°å²çªï¼è `Hashtable` ç´æ¥ä½¿ç¨é®ç `hashCode()` å¼ã
**`HashMap` ä¸å¸¦æåå§å®¹éçæé 彿°ï¼**
```java
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
```
ä¸é¢è¿ä¸ªæ¹æ³ä¿è¯äº `HashMap` æ»æ¯ä½¿ç¨ 2 çå¹ä½ä¸ºåå¸è¡¨ç大å°ã
```java
/**
* Returns a power of two size for the given target capacity.
*/
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
```
### HashMap å HashSet åºå«
å¦æä½ çè¿ `HashSet` æºç çè¯å°±åºè¯¥ç¥éï¼`HashSet` åºå±å°±æ¯åºäº `HashMap` å®ç°çãï¼`HashSet` çæºç é常é常å°ï¼å 为é¤äº `clone()`ã`writeObject()`ã`readObject()`æ¯ `HashSet` èªå·±ä¸å¾ä¸å®ç°ä¹å¤ï¼å
¶ä»æ¹æ³é½æ¯ç´æ¥è°ç¨ `HashMap` ä¸çæ¹æ³ã
| `HashMap` | `HashSet` |
| :------------------------------------: | :----------------------------------------------------------: |
| å®ç°äº `Map` æ¥å£ | å®ç° `Set` æ¥å£ |
| åå¨é®å¼å¯¹ | ä»
åå¨å¯¹è±¡ |
| è°ç¨ `put()`å map 䏿·»å å
ç´ | è°ç¨ `add()`æ¹æ³å `Set` 䏿·»å å
ç´ |
| `HashMap` 使ç¨é®ï¼Keyï¼è®¡ç® `hashcode` | `HashSet` ä½¿ç¨æå对象æ¥è®¡ç® `hashcode` å¼ï¼å¯¹äºä¸¤ä¸ªå¯¹è±¡æ¥è¯´ `hashcode` å¯è½ç¸åï¼æä»¥`equals()`æ¹æ³ç¨æ¥å¤æå¯¹è±¡çç¸çæ§ |
### âï¸HashMap å TreeMap åºå«
`TreeMap` å`HashMap` é½ç»§æ¿èª`AbstractMap` ï¼ä½æ¯éè¦æ³¨æçæ¯`TreeMap`å®è¿å®ç°äº`NavigableMap`æ¥å£å`SortedMap` æ¥å£ã

å®ç° `NavigableMap` æ¥å£è®© `TreeMap` æäºå¯¹éåå
å
ç´ çæç´¢çè½åã
`NavigableMap` æ¥å£æä¾äºä¸°å¯çæ¹æ³æ¥æ¢ç´¢åæä½é®å¼å¯¹:
1. **å®åæç´¢**: `ceilingEntry()`, `floorEntry()`, `higherEntry()`å `lowerEntry()` çæ¹æ³å¯ä»¥ç¨äºå®ä½å¤§äºçäºãå°äºçäºãä¸¥æ ¼å¤§äºãä¸¥æ ¼å°äºç»å®é®çææ¥è¿çé®å¼å¯¹ã
2. **åéæä½**: `subMap()`, `headMap()`å `tailMap()` æ¹æ³å¯ä»¥é«æå°å建åéåçåéè§å¾ï¼èæ éå¤å¶æ´ä¸ªéåã
3. **éåºè§å¾**:`descendingMap()` æ¹æ³è¿åä¸ä¸ªéåºç `NavigableMap` è§å¾ï¼ä½¿å¾å¯ä»¥ååè¿ä»£æ´ä¸ª `TreeMap`ã
4. **è¾¹çæä½**: `firstEntry()`, `lastEntry()`, `pollFirstEntry()`å `pollLastEntry()` çæ¹æ³å¯ä»¥æ¹ä¾¿å°è®¿é®åç§»é¤å
ç´ ã
è¿äºæ¹æ³é½æ¯åºäºçº¢é»æ æ°æ®ç»æç屿§å®ç°çï¼çº¢é»æ ä¿æå¹³è¡¡ç¶æï¼ä»èä¿è¯äºæç´¢æä½çæ¶é´å¤æåº¦ä¸º O(log n)ï¼è¿è®© `TreeMap` æä¸ºäºå¤çæåºéåæç´¢é®é¢ç强大工å
·ã
å®ç°`SortedMap`æ¥å£è®© `TreeMap` æäºå¯¹éåä¸çå
ç´ æ ¹æ®é®æåºçè½åãé»è®¤æ¯æ key çååºæåºï¼ä¸è¿æä»¬ä¹å¯ä»¥æå®æåºçæ¯è¾å¨ã示ä¾ä»£ç å¦ä¸ï¼
```java
/**
* @author shuang.kou
* @createTime 2020å¹´06æ15æ¥ 17:02:00
*/
public class Person {
private Integer age;
public Person(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
public static void main(String[] args) {
TreeMap treeMap = new TreeMap<>(new Comparator() {
@Override
public int compare(Person person1, Person person2) {
int num = person1.getAge() - person2.getAge();
return Integer.compare(num, 0);
}
});
treeMap.put(new Person(3), "person1");
treeMap.put(new Person(18), "person2");
treeMap.put(new Person(35), "person3");
treeMap.put(new Person(16), "person4");
treeMap.entrySet().stream().forEach(personStringEntry -> {
System.out.println(personStringEntry.getValue());
});
}
}
```
è¾åº:
```plain
person1
person4
person2
person3
```
å¯ä»¥çåºï¼`TreeMap` ä¸çå
ç´ å·²ç»æ¯æç
§ `Person` ç age åæ®µçååºæ¥æåäºã
ä¸é¢ï¼æä»¬æ¯éè¿ä¼ å
¥å¿åå
é¨ç±»çæ¹å¼å®ç°çï¼ä½ å¯ä»¥å°ä»£ç æ¿æ¢æ Lambda 表达å¼å®ç°çæ¹å¼ï¼
```java
TreeMap treeMap = new TreeMap<>((person1, person2) -> {
int num = person1.getAge() - person2.getAge();
return Integer.compare(num, 0);
});
```
**综ä¸ï¼ç¸æ¯äº`HashMap`æ¥è¯´ï¼ `TreeMap` 主è¦å¤äºå¯¹éåä¸çå
ç´ æ ¹æ®é®æåºçè½å以å对éåå
å
ç´ çæç´¢çè½åã**
### HashSet å¦ä½æ£æ¥éå¤?
以ä¸å
容æèªæç Java å¯è书ãHead first javaã第äºçï¼
> å½ä½ æå¯¹è±¡å å
¥`HashSet`æ¶ï¼`HashSet` ä¼å
计ç®å¯¹è±¡ç`hashcode`弿¥å¤æå¯¹è±¡å å
¥çä½ç½®ï¼åæ¶ä¹ä¼ä¸å
¶ä»å å
¥ç对象ç `hashcode` å¼ä½æ¯è¾ï¼å¦ææ²¡æç¸ç¬¦ç `hashcode`ï¼`HashSet` ä¼å设对象没æéå¤åºç°ã使¯å¦æåç°æç¸å `hashcode` å¼ç对象ï¼è¿æ¶ä¼è°ç¨`equals()`æ¹æ³æ¥æ£æ¥ `hashcode` ç¸çç对象æ¯å¦ççç¸åã妿䏤è
ç¸åï¼`HashSet` å°±ä¸ä¼è®©å å
¥æä½æåã
å¨ JDK1.8 ä¸ï¼`HashSet`ç`add()`æ¹æ³åªæ¯ç®åçè°ç¨äº`HashMap`ç`put()`æ¹æ³ï¼å¹¶ä¸å¤æäºä¸ä¸è¿åå¼ä»¥ç¡®ä¿æ¯å¦æéå¤å
ç´ ãç´æ¥çä¸ä¸`HashSet`ä¸çæºç ï¼
```java
// Returns: true if this set did not already contain the specified element
// è¿åå¼ï¼å½ set 䏿²¡æå
å« add çå
ç´ æ¶è¿åç
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
```
èå¨`HashMap`ç`putVal()`æ¹æ³ä¸ä¹è½çå°å¦ä¸è¯´æï¼
```java
// Returns : previous value, or null if none
// è¿åå¼ï¼å¦ææå
¥ä½ç½®æ²¡æå
ç´ è¿ånullï¼å¦åè¿åä¸ä¸ä¸ªå
ç´
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
...
}
```
ä¹å°±æ¯è¯´ï¼å¨ JDK1.8 ä¸ï¼å®é
䏿 论`HashSet`䏿¯å¦å·²ç»åå¨äºæå
ç´ ï¼`HashSet`é½ä¼ç´æ¥æå
¥ï¼åªæ¯ä¼å¨`add()`æ¹æ³çè¿åå¼å¤åè¯æä»¬æå
¥åæ¯å¦åå¨ç¸åå
ç´ ã
### âï¸HashMap çåºå±å®ç°
#### JDK1.8 ä¹å
JDK1.8 ä¹å `HashMap` åºå±æ¯ **æ°ç»åé¾è¡¨** ç»åå¨ä¸èµ·ä½¿ç¨ä¹å°±æ¯ **é¾è¡¨æ£å**ãHashMap éè¿ key ç `hashcode` ç»è¿æ°å¨å½æ°å¤çè¿åå¾å° hash å¼ï¼ç¶åéè¿ `(n - 1) & hash` 夿å½åå
ç´ åæ¾çä½ç½®ï¼è¿éç n æçæ¯æ°ç»çé¿åº¦ï¼ï¼å¦æå½åä½ç½®åå¨å
ç´ çè¯ï¼å°±å¤æè¯¥å
ç´ ä¸è¦åå
¥çå
ç´ ç hash å¼ä»¥å key æ¯å¦ç¸åï¼å¦æç¸åçè¯ï¼ç´æ¥è¦çï¼ä¸ç¸åå°±éè¿æé¾æ³è§£å³å²çªã
`HashMap` ä¸çæ°å¨å½æ°ï¼`hash` æ¹æ³ï¼æ¯ç¨æ¥ä¼ååå¸å¼çåå¸ãéè¿å¯¹åå§ç `hashCode()` è¿è¡é¢å¤å¤çï¼æ°å¨å½æ°å¯ä»¥åå°ç±äºç³ç³ç `hashCode()` å®ç°å¯¼è´ç碰æï¼ä»èæé«æ°æ®çåå¸ååæ§ã
**JDK 1.8 HashMap ç hash æ¹æ³æºç :**
JDK 1.8 ç hash æ¹æ³ ç¸æ¯äº JDK 1.7 hash æ¹æ³æ´å ç®åï¼ä½æ¯åçä¸åã
```java
static final int hash(Object key) {
int h;
// key.hashCode()ï¼è¿åæ£åå¼ä¹å°±æ¯hashcode
// ^ï¼æä½å¼æ
// >>>:æ 符å·å³ç§»ï¼å¿½ç¥ç¬¦å·ä½ï¼ç©ºä½é½ä»¥0è¡¥é½
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
```
对æ¯ä¸ä¸ JDK1.7 ç HashMap ç hash æ¹æ³æºç .
```java
static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
```
ç¸æ¯äº JDK1.8 ç hash æ¹æ³ ï¼JDK 1.7 ç hash æ¹æ³çæ§è½ä¼ç¨å·®ä¸ç¹ç¹ï¼å 为æ¯ç«æ°å¨äº 4 次ã
æè° **âæé¾æ³â** å°±æ¯ï¼å°é¾è¡¨åæ°ç»ç¸ç»åãä¹å°±æ¯è¯´å建ä¸ä¸ªé¾è¡¨æ°ç»ï¼æ°ç»ä¸æ¯ä¸æ ¼å°±æ¯ä¸ä¸ªé¾è¡¨ãè¥éå°åå¸å²çªï¼åå°å²çªçå¼å å°é¾è¡¨ä¸å³å¯ã

#### JDK1.8 ä¹å
ç¸æ¯äºä¹åççæ¬ï¼ JDK1.8 ä¹åå¨è§£å³åå¸å²çªæ¶æäºè¾å¤§çååï¼å½é¾è¡¨é¿åº¦å¤§äºéå¼ï¼é»è®¤ä¸º 8ï¼ï¼å°é¾è¡¨è½¬æ¢æçº¢é»æ åä¼å¤æï¼å¦æå½åæ°ç»çé¿åº¦å°äº 64ï¼é£ä¹ä¼éæ©å
è¿è¡æ°ç»æ©å®¹ï¼è䏿¯è½¬æ¢ä¸ºçº¢é»æ ï¼æ¶ï¼å°é¾è¡¨è½¬åä¸ºçº¢é»æ ã
è¿æ ·åçç®çæ¯åå°æç´¢æ¶é´ï¼é¾è¡¨çæ¥è¯¢æç为 O(n)ï¼n æ¯é¾è¡¨çé¿åº¦ï¼ï¼çº¢é»æ æ¯ä¸ç§èªå¹³è¡¡äºåæç´¢æ ï¼å
¶æ¥è¯¢æç为 O(log n)ãå½é¾è¡¨è¾çæ¶ï¼O(n) å O(log n) çæ§è½å·®å¼ä¸ææ¾ãä½å½é¾è¡¨åé¿æ¶ï¼æ¥è¯¢æ§è½ä¼æ¾èä¸éã

**为ä»ä¹ä¼å
æ©å®¹èéç´æ¥è½¬ä¸ºçº¢é»æ ï¼**
æ°ç»æ©å®¹è½åå°åå¸å²çªçåçæ¦çï¼å³å°å
ç´ éæ°åæ£å°æ°çãæ´å¤§çæ°ç»ä¸ï¼ï¼è¿å¨å¤æ°æ
åµä¸æ¯ç´æ¥è½¬æ¢ä¸ºçº¢é»æ æ´é«æã
çº¢é»æ éè¦ä¿æèªå¹³è¡¡ï¼ç»´æ¤ææ¬è¾é«ãå¹¶ä¸ï¼è¿æ©å¼å
¥çº¢é»æ åèä¼å¢å å¤æåº¦ã
**为ä»ä¹éæ©éå¼ 8 å 64ï¼**
1. æ³æ¾åå¸è¡¨æï¼é¾è¡¨é¿åº¦è¾¾å° 8 çæ¦çæä½ï¼å°äºåä¸åä¹ä¸ï¼ãå¨ç»å¤§å¤æ°æ
åµä¸ï¼é¾è¡¨é¿åº¦é½ä¸ä¼è¶
è¿ 8ãéå¼è®¾ç½®ä¸º 8ï¼å¯ä»¥ä¿è¯æ§è½åç©ºé´æçç平衡ã
2. æ°ç»é¿åº¦éå¼ 64 åæ ·æ¯ç»è¿å®è·µéªè¯çç»éªå¼ãå¨å°æ°ç»ä¸æ©å®¹ææ¬ä½ï¼ä¼å
æ©å®¹å¯ä»¥é¿å
è¿æ©å¼å
¥çº¢é»æ ãæ°ç»å¤§å°è¾¾å° 64 æ¶ï¼å²çªæ¦çè¾é«ï¼æ¤æ¶çº¢é»æ çæ§è½ä¼å¿å¼å§æ¾ç°ã
> TreeMapãTreeSet 以å JDK1.8 ä¹åç HashMap åºå±é½ç¨å°äºçº¢é»æ ãçº¢é»æ å°±æ¯ä¸ºäºè§£å³äºåæ¥æ¾æ ç缺é·ï¼å 为äºåæ¥æ¾æ å¨æäºæ
åµä¸ä¼éåæä¸ä¸ªçº¿æ§ç»æã
æä»¬æ¥ç»åæºç åæä¸ä¸ `HashMap` é¾è¡¨å°çº¢é»æ ç转æ¢ã
**1ã `putVal` æ¹æ³ä¸æ§è¡é¾è¡¨è½¬çº¢é»æ ç夿é»è¾ã**
é¾è¡¨çé¿åº¦å¤§äº 8 çæ¶åï¼å°±æ§è¡ `treeifyBin` ï¼è½¬æ¢çº¢é»æ ï¼çé»è¾ã
```java
// éåé¾è¡¨
for (int binCount = 0; ; ++binCount) {
// éåå°é¾è¡¨æåä¸ä¸ªèç¹
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
// 妿é¾è¡¨å
ç´ ä¸ªæ°å¤§äºTREEIFY_THRESHOLDï¼8ï¼
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
// çº¢é»æ 转æ¢ï¼å¹¶ä¸ä¼ç´æ¥è½¬æ¢æçº¢é»æ ï¼
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
```
**2ã`treeifyBin` æ¹æ³ä¸å¤ææ¯å¦çç转æ¢ä¸ºçº¢é»æ ã**
```java
final void treeifyBin(Node[] tab, int hash) {
int n, index; Node e;
// 夿å½åæ°ç»çé¿åº¦æ¯å¦å°äº 64
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
// 妿å½åæ°ç»çé¿åº¦å°äº 64ï¼é£ä¹ä¼éæ©å
è¿è¡æ°ç»æ©å®¹
resize();
else if ((e = tab[index = (n - 1) & hash]) != null) {
// å¦åæå°å表转æ¢ä¸ºçº¢é»æ
TreeNode hd = null, tl = null;
do {
TreeNode p = replacementTreeNode(e, null);
if (tl == null)
hd = p;
else {
p.prev = tl;
tl.next = p;
}
tl = p;
} while ((e = e.next) != null);
if ((tab[index] = hd) != null)
hd.treeify(tab);
}
}
```
å°é¾è¡¨è½¬æ¢æçº¢é»æ åä¼å¤æï¼å¦æå½åæ°ç»çé¿åº¦å°äº 64ï¼é£ä¹ä¼éæ©å
è¿è¡æ°ç»æ©å®¹ï¼è䏿¯è½¬æ¢ä¸ºçº¢é»æ ã
### âï¸HashMap çé¿åº¦ä¸ºä»ä¹æ¯ 2 ç广¬¡æ¹
为äºè®© `HashMap` åå髿并åå°ç¢°æï¼æä»¬éè¦ç¡®ä¿æ°æ®å°½éåååå¸ãåå¸å¼å¨ Java ä¸éå¸¸ä½¿ç¨ `int` 表示ï¼å
¶èå´æ¯ `-2147483648 ~ 2147483647`ååå èµ·æ¥å¤§æ¦ 40 äº¿çæ å°ç©ºé´ï¼åªè¦åå¸å½æ°æ å°å¾æ¯è¾ååæ¾æ£ï¼ä¸è¬åºç¨æ¯å¾é¾åºç°ç¢°æçã使¯ï¼é®é¢æ¯ä¸ä¸ª 40 亿é¿åº¦çæ°ç»ï¼å
忝æ¾ä¸ä¸çãæä»¥ï¼è¿ä¸ªæ£å弿¯ä¸è½ç´æ¥æ¿æ¥ç¨çãç¨ä¹åè¿è¦å
å对æ°ç»çé¿åº¦å模è¿ç®ï¼å¾å°ç使°æè½ç¨æ¥è¦åæ¾çä½ç½®ä¹å°±æ¯å¯¹åºçæ°ç»ä¸æ ã
**è¿ä¸ªç®æ³åºè¯¥å¦ä½è®¾è®¡å¢ï¼**
æä»¬é¦å
å¯è½ä¼æ³å°éç¨ % åä½çæä½æ¥å®ç°ã使¯ï¼éç¹æ¥äºï¼â**åä½(%)æä½ä¸å¦æé¤æ°æ¯ 2 ç广¬¡åçä»·äºä¸å
¶é¤æ°åä¸çä¸(&)æä½**ï¼ä¹å°±æ¯è¯´ `hash%length==hash&(length-1)` çåææ¯ length æ¯ 2 ç n 次æ¹ï¼ãâ å¹¶ä¸ï¼**éç¨äºè¿å¶ä½æä½ & ç¸å¯¹äº % è½å¤æé«è¿ç®æç**ã
é¤äºä¸é¢æè¯´çä½è¿ç®æ¯å使çé«ä¹å¤ï¼æè§å¾æ´éè¦çä¸ä¸ªåå æ¯ï¼**é¿åº¦æ¯ 2 ç广¬¡æ¹ï¼å¯ä»¥è®© `HashMap` 卿©å®¹çæ¶åæ´åå**ãä¾å¦:
- length = 8 æ¶ï¼length - 1 = 7 çäºè¿å¶ä½`0111`
- length = 16 æ¶ï¼length - 1 = 15 çäºè¿å¶ä½`1111`
è¿æ¶å忬åå¨ `HashMap` ä¸çå
ç´ è®¡ç®æ°çæ°ç»ä½ç½®æ¶ `hash&(length-1)`ï¼åå³ hash ç第å个äºè¿å¶ä½ï¼ä»å³æ°ï¼ï¼ä¼åºç°ä¸¤ç§æ
åµï¼
1. 第å个äºè¿å¶ä½ä¸º 0ï¼æ°ç»ä½ç½®ä¸åï¼ä¹å°±æ¯è¯´å½åå
ç´ å¨æ°æ°ç»åæ§æ°ç»çä½ç½®ç¸åã
2. 第å个äºè¿å¶ä½ä¸º 1ï¼æ°ç»ä½ç½®å¨æ°æ°ç»æ©å®¹ä¹åçé£ä¸é¨åã
è¿éå举ä¸ä¸ªä¾åï¼
```plain
å设æä¸ä¸ªå
ç´ çåå¸å¼ä¸º 10101100
æ§æ°ç»å
ç´ ä½ç½®è®¡ç®ï¼
hash = 10101100
length - 1 = 00000111
& -----------------
index = 00000100 (4)
æ°æ°ç»å
ç´ ä½ç½®è®¡ç®ï¼
hash = 10101100
length - 1 = 00001111
& -----------------
index = 00001100 (12)
ç第åä½ï¼ä»å³æ°ï¼ï¼
1.é«ä½ä¸º 0ï¼ä½ç½®ä¸åã
2.é«ä½ä¸º 1ï¼ç§»å¨å°æ°ä½ç½®ï¼åç´¢å¼ä½ç½®+å容éï¼ã
```
â ï¸æ³¨æï¼è¿éå举çåºæ¯ççæ¯ç¬¬å个äºè¿å¶ä½ï¼æ´åç¡®ç¹æ¥è¯´ççæ¯é«ä½ï¼ä»å³æ°ï¼ï¼ä¾å¦ `length = 32` æ¶ï¼`length - 1 = 31`ï¼äºè¿å¶ä¸º `11111`ï¼è¿éççå°±æ¯ç¬¬äºä¸ªäºè¿å¶ä½ã
ä¹å°±æ¯è¯´æ©å®¹ä¹åï¼å¨æ§æ°ç»å
ç´ hash 弿¯è¾ååï¼è³äº hash å¼åä¸ååï¼åå³äºåé¢è®²ç对象ç `hashcode()` æ¹æ³åæ°å¨å½æ°ï¼çæ
åµä¸ï¼æ°æ°ç»å
ç´ ä¹ä¼è¢«åé
çæ¯è¾ååï¼æå¥½çæ
嵿¯ä¼æä¸å卿°æ°ç»çååé¨åï¼ä¸å卿°æ°ç»ååé¨åã
è¿æ ·ä¹ä½¿å¾æ©å®¹æºå¶åå¾ç®ååé«æï¼æ©å®¹ååªéæ£æ¥åå¸å¼é«ä½çå忥å³å®å
ç´ çæ°ä½ç½®ï¼è¦ä¹ä½ç½®ä¸åï¼é«ä½ä¸º 0ï¼ï¼è¦ä¹å°±æ¯ç§»å¨å°æ°ä½ç½®ï¼é«ä½ä¸º 1ï¼åç´¢å¼ä½ç½®+å容éï¼ã
æåï¼ç®åæ»ç»ä¸ä¸ `HashMap` çé¿åº¦æ¯ 2 ç广¬¡æ¹çåå ï¼
1. ä½è¿ç®æçæ´é«ï¼ä½è¿ç®(&)æ¯åä½è¿ç®(%)æ´é«æãå½é¿åº¦ä¸º 2 ç广¬¡æ¹æ¶ï¼`hash % length` çä»·äº `hash & (length - 1)`ã
2. å¯ä»¥æ´å¥½å°ä¿è¯åå¸å¼çåååå¸ï¼æ©å®¹ä¹åï¼å¨æ§æ°ç»å
ç´ hash 弿¯è¾ååçæ
åµä¸ï¼æ°æ°ç»å
ç´ ä¹ä¼è¢«åé
çæ¯è¾ååï¼æå¥½çæ
嵿¯ä¼æä¸å卿°æ°ç»çååé¨åï¼ä¸å卿°æ°ç»ååé¨åã
3. æ©å®¹æºå¶åå¾ç®ååé«æï¼æ©å®¹ååªéæ£æ¥åå¸å¼é«ä½çå忥å³å®å
ç´ çæ°ä½ç½®ï¼è¦ä¹ä½ç½®ä¸åï¼é«ä½ä¸º 0ï¼ï¼è¦ä¹å°±æ¯ç§»å¨å°æ°ä½ç½®ï¼é«ä½ä¸º 1ï¼åç´¢å¼ä½ç½®+å容éï¼ã
### âï¸HashMap å¤çº¿ç¨æä½å¯¼è´æ»å¾ªç¯é®é¢
JDK1.7 åä¹åçæ¬ç `HashMap` å¨å¤çº¿ç¨ç¯å¢ä¸æ©å®¹æä½å¯è½å卿»å¾ªç¯é®é¢ï¼è¿æ¯ç±äºå½ä¸ä¸ªæ¡¶ä½ä¸æå¤ä¸ªå
ç´ éè¦è¿è¡æ©å®¹æ¶ï¼å¤ä¸ªçº¿ç¨åæ¶å¯¹é¾è¡¨è¿è¡æä½ï¼å¤´ææ³å¯è½ä¼å¯¼è´é¾è¡¨ä¸çèç¹æåé误çä½ç½®ï¼ä»èå½¢æä¸ä¸ªç¯å½¢é¾è¡¨ï¼è¿èä½¿å¾æ¥è¯¢å
ç´ çæä½é·å
¥æ»å¾ªç¯æ æ³ç»æã
为äºè§£å³è¿ä¸ªé®é¢ï¼JDK1.8 çæ¬ç HashMap éç¨äºå°¾ææ³è䏿¯å¤´ææ³æ¥é¿å
é¾è¡¨åç½®ï¼ä½¿å¾æå
¥çèç¹æ°¸è¿é½æ¯æ¾å¨é¾è¡¨çæ«å°¾ï¼é¿å
äºé¾è¡¨ä¸çç¯å½¢ç»æã使¯è¿æ¯ä¸å»ºè®®å¨å¤çº¿ç¨ä¸ä½¿ç¨ `HashMap`ï¼å 为å¤çº¿ç¨ä¸ä½¿ç¨ `HashMap` è¿æ¯ä¼å卿°æ®è¦ççé®é¢ãå¹¶åç¯å¢ä¸ï¼æ¨èä½¿ç¨ `ConcurrentHashMap` ã
ä¸è¬é¢è¯ä¸è¿æ ·ä»ç»å°±å·®ä¸å¤ï¼ä¸éè¦è®°åç§ç»èï¼ä¸ªäººè§å¾ä¹æ²¡å¿
è¦è®°ã妿æ³è¦è¯¦ç»äºè§£ `HashMap` æ©å®¹å¯¼è´æ»å¾ªç¯é®é¢ï¼å¯ä»¥ççèååçè¿ç¯æç« ï¼[Java HashMap çæ»å¾ªç¯](https://coolshell.cn/articles/9606.html)ã
### âï¸HashMap 为ä»ä¹çº¿ç¨ä¸å®å
¨ï¼
JDK1.7 åä¹åçæ¬ï¼å¨å¤çº¿ç¨ç¯å¢ä¸ï¼`HashMap` æ©å®¹æ¶ä¼é ææ»å¾ªç¯åæ°æ®ä¸¢å¤±çé®é¢ã
æ°æ®ä¸¢å¤±è¿ä¸ªå¨ JDK1.7 å JDK 1.8 ä¸é½åå¨ï¼è¿é以 JDK 1.8 为ä¾è¿è¡ä»ç»ã
JDK 1.8 åï¼å¨ `HashMap` ä¸ï¼å¤ä¸ªé®å¼å¯¹å¯è½ä¼è¢«åé
å°åä¸ä¸ªæ¡¶ï¼bucketï¼ï¼å¹¶ä»¥é¾è¡¨æçº¢é»æ çå½¢å¼åå¨ãå¤ä¸ªçº¿ç¨å¯¹ `HashMap` ç `put` æä½ä¼å¯¼è´çº¿ç¨ä¸å®å
¨ï¼å
·ä½æ¥è¯´ä¼ææ°æ®è¦ççé£é©ã
举个ä¾åï¼
- ä¸¤ä¸ªçº¿ç¨ 1,2 åæ¶è¿è¡ put æä½ï¼å¹¶ä¸åçäºåå¸å²çªï¼hash 彿°è®¡ç®åºçæå
¥ä¸æ æ¯ç¸åçï¼ã
- ä¸åç线ç¨å¯è½å¨ä¸åçæ¶é´çè·å¾ CPU æ§è¡çæºä¼ï¼å½åçº¿ç¨ 1 æ§è¡å®åå¸å²çªå¤æåï¼ç±äºæ¶é´çèå°½æèµ·ãçº¿ç¨ 2 å
å®æäºæå
¥æä½ã
- éåï¼çº¿ç¨ 1 è·å¾æ¶é´çï¼ç±äºä¹åå·²ç»è¿è¡è¿ hash 碰æçå¤æï¼æææ¤æ¶ä¼ç´æ¥è¿è¡æå
¥ï¼è¿å°±å¯¼è´çº¿ç¨ 2 æå
¥çæ°æ®è¢«çº¿ç¨ 1 è¦çäºã
```java
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
// ...
// 夿æ¯å¦åºç° hash 碰æ
// (n - 1) & hash ç¡®å®å
ç´ åæ¾å¨åªä¸ªæ¡¶ä¸ï¼æ¡¶ä¸ºç©ºï¼æ°çæç»ç¹æ¾å
¥æ¡¶ä¸(æ¤æ¶ï¼è¿ä¸ªç»ç¹æ¯æ¾å¨æ°ç»ä¸)
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
// æ¡¶ä¸å·²ç»åå¨å
ç´ ï¼å¤çhashå²çªï¼
else {
// ...
}
```
è¿æä¸ç§æ
嵿¯è¿ä¸¤ä¸ªçº¿ç¨åæ¶ `put` æä½å¯¼è´ `size` çå¼ä¸æ£ç¡®ï¼è¿èå¯¼è´æ°æ®è¦ççé®é¢ï¼
1. çº¿ç¨ 1 æ§è¡ `if(++size > threshold)` 夿æ¶ï¼å设è·å¾ `size` çå¼ä¸º 10ï¼ç±äºæ¶é´çèå°½æèµ·ã
2. çº¿ç¨ 2 乿§è¡ `if(++size > threshold)` 夿ï¼è·å¾ `size` çå¼ä¹ä¸º 10ï¼å¹¶å°å
ç´ æå
¥å°è¯¥æ¡¶ä½ä¸ï¼å¹¶å° `size` ç弿´æ°ä¸º 11ã
3. éåï¼çº¿ç¨ 1 è·å¾æ¶é´çï¼å®ä¹å°å
ç´ æ¾å
¥æ¡¶ä½ä¸ï¼å¹¶å° size ç弿´æ°ä¸º 11ã
4. çº¿ç¨ 1ã2 齿§è¡äºä¸æ¬¡ `put` æä½ï¼ä½æ¯ `size` çå¼åªå¢å äº 1ï¼ä¹å°±å¯¼è´å®é
ä¸åªæä¸ä¸ªå
ç´ è¢«æ·»å å°äº `HashMap` ä¸ã
```java
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
// ...
// å®é
大å°å¤§äºéå¼åæ©å®¹
if (++size > threshold)
resize();
// æå
¥ååè°
afterNodeInsertion(evict);
return null;
}
```
### HashMap 常è§çéåæ¹å¼?
[HashMap ç 7 ç§éåæ¹å¼ä¸æ§è½åæï¼](https://mp.weixin.qq.com/s/zQBN3UvJDhRTKP6SzcZFKw)
**ð ä¿®æ£ï¼åè§ï¼[issue#1411](https://github.com/Snailclimb/JavaGuide/issues/1411)ï¼**ï¼
è¿ç¯æç« å¯¹äº parallelStream éåæ¹å¼çæ§è½åææè¯¯ï¼å
说ç»è®ºï¼**åå¨é»å¡æ¶ parallelStream æ§è½æé«, éé»å¡æ¶ parallelStream æ§è½æä½** ã
å½éåä¸åå¨é»å¡æ¶, parallelStream çæ§è½æ¯æä½çï¼
```plain
Benchmark Mode Cnt Score Error Units
Test.entrySet avgt 5 288.651 ± 10.536 ns/op
Test.keySet avgt 5 584.594 ± 21.431 ns/op
Test.lambda avgt 5 221.791 ± 10.198 ns/op
Test.parallelStream avgt 5 6919.163 ± 1116.139 ns/op
```
å å
¥é»å¡ä»£ç `Thread.sleep(10)`å, parallelStream çæ§è½ææ¯æé«ç:
```plain
Benchmark Mode Cnt Score Error Units
Test.entrySet avgt 5 1554828440.000 ± 23657748.653 ns/op
Test.keySet avgt 5 1550612500.000 ± 6474562.858 ns/op
Test.lambda avgt 5 1551065180.000 ± 19164407.426 ns/op
Test.parallelStream avgt 5 186345456.667 ± 3210435.590 ns/op
```
### âï¸ConcurrentHashMap å Hashtable çåºå«
`ConcurrentHashMap` å `Hashtable` çåºå«ä¸»è¦ä½ç°å¨å®ç°çº¿ç¨å®å
¨çæ¹å¼ä¸ä¸åã
- **åºå±æ°æ®ç»æï¼** JDK1.7 ç `ConcurrentHashMap` åºå±éç¨ **åæ®µçæ°ç»+é¾è¡¨** å®ç°ï¼å¨ JDK1.8 ä¸éç¨çæ°æ®ç»æè· `HashMap` çç»æä¸æ ·ï¼æ°ç»+é¾è¡¨/红é»äºåæ ã`Hashtable` å JDK1.8 ä¹åç `HashMap` çåºå±æ°æ®ç»æç±»ä¼¼é½æ¯éç¨ **æ°ç»+é¾è¡¨** çå½¢å¼ï¼æ°ç»æ¯ HashMap ç主ä½ï¼é¾è¡¨åæ¯ä¸»è¦ä¸ºäºè§£å³åå¸å²çªèåå¨çï¼
- **å®ç°çº¿ç¨å®å
¨çæ¹å¼ï¼éè¦ï¼ï¼**
- å¨ JDK1.7 çæ¶åï¼`ConcurrentHashMap` 对æ´ä¸ªæ¡¶æ°ç»è¿è¡äºåå²å段(`Segment`ï¼å段é)ï¼æ¯ä¸æéåªé容å¨å
¶ä¸ä¸é¨åæ°æ®ï¼ä¸é¢æç¤ºæå¾ï¼ï¼å¤çº¿ç¨è®¿é®å®¹å¨éä¸åæ°æ®æ®µçæ°æ®ï¼å°±ä¸ä¼åå¨éç«äºï¼æé«å¹¶å访é®çã
- å°äº JDK1.8 çæ¶åï¼`ConcurrentHashMap` å·²ç»æå¼äº `Segment` çæ¦å¿µï¼èæ¯ç´æ¥ç¨ `Node` æ°ç»+é¾è¡¨+çº¢é»æ çæ°æ®ç»ææ¥å®ç°ï¼å¹¶åæ§å¶ä½¿ç¨ `synchronized` å CAS æ¥æä½ãï¼JDK1.6 以å `synchronized` éåäºå¾å¤ä¼åï¼ æ´ä¸ªçèµ·æ¥å°±åæ¯ä¼åè¿ä¸çº¿ç¨å®å
¨ç `HashMap`ï¼è½ç¶å¨ JDK1.8 ä¸è¿è½çå° `Segment` çæ°æ®ç»æï¼ä½æ¯å·²ç»ç®åäºå±æ§ï¼åªæ¯ä¸ºäºå
¼å®¹æ§çæ¬ï¼
- **`Hashtable`(å䏿é)** :ä½¿ç¨ `synchronized` æ¥ä¿è¯çº¿ç¨å®å
¨ï¼æçé常ä½ä¸ãå½ä¸ä¸ªçº¿ç¨è®¿é®åæ¥æ¹æ³æ¶ï¼å
¶ä»çº¿ç¨ä¹è®¿é®åæ¥æ¹æ³ï¼å¯è½ä¼è¿å
¥é»å¡æè½®è¯¢ç¶æï¼å¦ä½¿ç¨ put æ·»å å
ç´ ï¼å¦ä¸ä¸ªçº¿ç¨ä¸è½ä½¿ç¨ put æ·»å å
ç´ ï¼ä¹ä¸è½ä½¿ç¨ getï¼ç«äºä¼è¶æ¥è¶æ¿çæçè¶ä½ã
ä¸é¢ï¼æä»¬åæ¥çç两è
åºå±æ°æ®ç»æç对æ¯å¾ã
**Hashtable** :

https://www.cnblogs.com/chengxiao/p/6842045.html>
**JDK1.7 ç ConcurrentHashMap**ï¼

`ConcurrentHashMap` æ¯ç± `Segment` æ°ç»ç»æå `HashEntry` æ°ç»ç»æç»æã
`Segment` æ°ç»ä¸çæ¯ä¸ªå
ç´ å
å«ä¸ä¸ª `HashEntry` æ°ç»ï¼æ¯ä¸ª `HashEntry` æ°ç»å±äºé¾è¡¨ç»æã
**JDK1.8 ç ConcurrentHashMap**ï¼

JDK1.8 ç `ConcurrentHashMap` ä¸åæ¯ **Segment æ°ç» + HashEntry æ°ç» + é¾è¡¨**ï¼èæ¯ **Node æ°ç» + é¾è¡¨ / çº¢é»æ **ãä¸è¿ï¼Node åªè½ç¨äºé¾è¡¨çæ
åµï¼çº¢é»æ çæ
åµéè¦ä½¿ç¨ **`TreeNode`**ãå½å²çªé¾è¡¨è¾¾å°ä¸å®é¿åº¦æ¶ï¼é¾è¡¨ä¼è½¬æ¢æçº¢é»æ ã
`TreeNode`æ¯åå¨çº¢é»æ èç¹ï¼è¢«`TreeBin`å
è£
ã`TreeBin`éè¿`root`屿§ç»´æ¤çº¢é»æ çæ ¹ç»ç¹ï¼å ä¸ºçº¢é»æ å¨æè½¬çæ¶åï¼æ ¹ç»ç¹å¯è½ä¼è¢«å®åæ¥çåèç¹æ¿æ¢æï¼å¨è¿ä¸ªæ¶é´ç¹ï¼å¦ææå
¶ä»çº¿ç¨è¦åè¿æ£µçº¢é»æ å°±ä¼åç线ç¨ä¸å®å
¨é®é¢ï¼æä»¥å¨ `ConcurrentHashMap` ä¸`TreeBin`éè¿`waiter`屿§ç»´æ¤å½å使ç¨è¿æ£µçº¢é»æ ç线ç¨ï¼æ¥é²æ¢å
¶ä»çº¿ç¨çè¿å
¥ã
```java
static final class TreeBin extends Node {
TreeNode root;
volatile TreeNode first;
volatile Thread waiter;
volatile int lockState;
// values for lockState
static final int WRITER = 1; // set while holding write lock
static final int WAITER = 2; // set when waiting for write lock
static final int READER = 4; // increment value for setting read lock
...
}
```
### âï¸ConcurrentHashMap 线ç¨å®å
¨çå
·ä½å®ç°æ¹å¼/åºå±å
·ä½å®ç°
#### JDK1.8 ä¹å

é¦å
å°æ°æ®åä¸ºä¸æ®µä¸æ®µï¼è¿ä¸ªâ段âå°±æ¯ `Segment`ï¼çåå¨ï¼ç¶åç»æ¯ä¸æ®µæ°æ®é
䏿éï¼å½ä¸ä¸ªçº¿ç¨å ç¨é访é®å
¶ä¸ä¸ä¸ªæ®µæ°æ®æ¶ï¼å
¶ä»æ®µçæ°æ®ä¹è½è¢«å
¶ä»çº¿ç¨è®¿é®ã
**`ConcurrentHashMap` æ¯ç± `Segment` æ°ç»ç»æå `HashEntry` æ°ç»ç»æç»æ**ã
`Segment` ç»§æ¿äº `ReentrantLock`,æä»¥ `Segment` æ¯ä¸ç§å¯éå
¥éï¼æ®æ¼éçè§è²ã`HashEntry` ç¨äºåå¨é®å¼å¯¹æ°æ®ã
```java
static class Segment extends ReentrantLock implements Serializable {
}
```
ä¸ä¸ª `ConcurrentHashMap` éå
å«ä¸ä¸ª `Segment` æ°ç»ï¼`Segment` ç个æ°ä¸æ¦**åå§åå°±ä¸è½æ¹å**ã `Segment` æ°ç»ç大å°é»è®¤æ¯ 16ï¼ä¹å°±æ¯è¯´é»è®¤å¯ä»¥åæ¶æ¯æ 16 个线ç¨å¹¶ååã
`Segment` çç»æå `HashMap` ç±»ä¼¼ï¼æ¯ä¸ç§æ°ç»åé¾è¡¨ç»æï¼ä¸ä¸ª `Segment` å
å«ä¸ä¸ª `HashEntry` æ°ç»ï¼æ¯ä¸ª `HashEntry` æ¯ä¸ä¸ªé¾è¡¨ç»æçå
ç´ ï¼æ¯ä¸ª `Segment` 宿¤çä¸ä¸ª `HashEntry` æ°ç»éçå
ç´ ï¼å½å¯¹ `HashEntry` æ°ç»çæ°æ®è¿è¡ä¿®æ¹æ¶ï¼å¿
é¡»é¦å
è·å¾å¯¹åºç `Segment` çéãä¹å°±æ¯è¯´ï¼å¯¹åä¸ `Segment` çå¹¶ååå
¥ä¼è¢«é»å¡ï¼ä¸å `Segment` çåå
¥æ¯å¯ä»¥å¹¶åæ§è¡çã
#### JDK1.8 ä¹å

Java 8 å ä¹å®å
¨éåäº `ConcurrentHashMap`ï¼ä»£ç éä»åæ¥ Java 7 ä¸ç 1000 å¤è¡ï¼åæäºç°å¨ç 6000 å¤è¡ã
`ConcurrentHashMap` åæ¶äº `Segment` åæ®µéï¼éç¨ `Node + CAS + synchronized` æ¥ä¿è¯å¹¶åå®å
¨ãæ°æ®ç»æè· `HashMap` 1.8 çç»æç±»ä¼¼ï¼æ°ç»+é¾è¡¨/红é»äºåæ ãJava 8 å¨é¾è¡¨é¿åº¦è¶
è¿ä¸å®éå¼ï¼8ï¼æ¶å°é¾è¡¨ï¼å¯»åæ¶é´å¤æåº¦ä¸º O(N)ï¼è½¬æ¢ä¸ºçº¢é»æ ï¼å¯»åæ¶é´å¤æåº¦ä¸º O(log(N))ï¼ã
Java 8 ä¸ï¼éç²åº¦æ´ç»ï¼`synchronized` åªéå®å½åé¾è¡¨æçº¢é»äºåæ çé¦èç¹ï¼è¿æ ·åªè¦ hash ä¸å²çªï¼å°±ä¸ä¼äº§çå¹¶åï¼å°±ä¸ä¼å½±åå
¶ä» Node ç读åï¼æç大å¹
æåã
### âï¸JDK 1.7 å JDK 1.8 ç ConcurrentHashMap å®ç°æä»ä¹ä¸åï¼
- **线ç¨å®å
¨å®ç°æ¹å¼**ï¼JDK 1.7 éç¨ `Segment` åæ®µéæ¥ä¿è¯å®å
¨ï¼ `Segment` æ¯ç»§æ¿èª `ReentrantLock`ãJDK1.8 æ¾å¼äº `Segment` åæ®µéç设计ï¼éç¨ `Node + CAS + synchronized` ä¿è¯çº¿ç¨å®å
¨ï¼éç²åº¦æ´ç»ï¼`synchronized` åªéå®å½åé¾è¡¨æçº¢é»äºåæ çé¦èç¹ã
- **Hash 碰æè§£å³æ¹æ³** : JDK 1.7 éç¨æé¾æ³ï¼JDK1.8 éç¨æé¾æ³ç»åçº¢é»æ ï¼é¾è¡¨é¿åº¦è¶
è¿ä¸å®é弿¶ï¼å°é¾è¡¨è½¬æ¢ä¸ºçº¢é»æ ï¼ã
- **å¹¶å度**ï¼JDK 1.7 æå¤§å¹¶ååº¦æ¯ Segment ç个æ°ï¼é»è®¤æ¯ 16ãJDK 1.8 æå¤§å¹¶ååº¦æ¯ Node æ°ç»ç大å°ï¼å¹¶å度æ´å¤§ã
### ConcurrentHashMap 为ä»ä¹ key å value ä¸è½ä¸º nullï¼
`ConcurrentHashMap` ç key å value ä¸è½ä¸º null ä¸»è¦æ¯ä¸ºäºé¿å
äºä¹æ§ãnull æ¯ä¸ä¸ªç¹æ®çå¼ï¼è¡¨ç¤ºæ²¡æå¯¹è±¡ææ²¡æå¼ç¨ãå¦æä½ ç¨ null ä½ä¸ºé®ï¼é£ä¹ä½ å°±æ æ³åºåè¿ä¸ªé®æ¯å¦åå¨äº `ConcurrentHashMap` ä¸ï¼è¿æ¯æ ¹æ¬æ²¡æè¿ä¸ªé®ãåæ ·ï¼å¦æä½ ç¨ null ä½ä¸ºå¼ï¼é£ä¹ä½ å°±æ æ³åºåè¿ä¸ªå¼æ¯å¦æ¯çæ£åå¨å¨ `ConcurrentHashMap` ä¸çï¼è¿æ¯å 为æ¾ä¸å°å¯¹åºçé®èè¿åçã
æ¿ get æ¹æ³å弿¥è¯´ï¼è¿åçç»æä¸º null åå¨ä¸¤ç§æ
åµï¼
- 弿²¡æå¨éåä¸ ï¼
- 弿¬èº«å°±æ¯ nullã
è¿ä¹å°±æ¯äºä¹æ§çç±æ¥ã
å
·ä½å¯ä»¥åè [ConcurrentHashMap æºç åæ](https://javaguide.cn/java/collection/concurrent-hash-map-source-code.html) ã
å¤çº¿ç¨ç¯å¢ä¸ï¼åå¨ä¸ä¸ªçº¿ç¨æä½è¯¥ `ConcurrentHashMap` æ¶ï¼å
¶ä»ç线ç¨å°è¯¥ `ConcurrentHashMap` ä¿®æ¹çæ
åµï¼æä»¥æ æ³éè¿ `containsKey(key)` æ¥å¤æå¦åå¨è¿ä¸ªé®å¼å¯¹ï¼ä¹å°±æ²¡åæ³è§£å³äºä¹æ§é®é¢äºã
䏿¤å½¢æå¯¹æ¯çæ¯ï¼`HashMap` å¯ä»¥åå¨ null ç key å valueï¼ä½ null ä½ä¸ºé®åªè½æä¸ä¸ªï¼null ä½ä¸ºå¼å¯ä»¥æå¤ä¸ªãå¦æä¼ å
¥ null ä½ä¸ºåæ°ï¼å°±ä¼è¿å hash å¼ä¸º 0 çä½ç½®çå¼ãå线ç¨ç¯å¢ä¸ï¼ä¸åå¨ä¸ä¸ªçº¿ç¨æä½è¯¥ HashMap æ¶ï¼å
¶ä»ç线ç¨å°è¯¥ `HashMap` ä¿®æ¹çæ
åµï¼æä»¥å¯ä»¥éè¿ `contains(key)`æ¥å夿æ¯å¦åå¨è¿ä¸ªé®å¼å¯¹ï¼ä»èåç¸åºçå¤çï¼ä¹å°±ä¸åå¨äºä¹æ§é®é¢ã
ä¹å°±æ¯è¯´ï¼å¤çº¿ç¨ä¸æ æ³æ£ç¡®å¤å®é®å¼å¯¹æ¯å¦åå¨ï¼åå¨å
¶ä»çº¿ç¨ä¿®æ¹çæ
åµï¼ï¼åçº¿ç¨æ¯å¯ä»¥çï¼ä¸åå¨å
¶ä»çº¿ç¨ä¿®æ¹çæ
åµï¼ã
å¦æä½ ç¡®å®éè¦å¨ ConcurrentHashMap ä¸ä½¿ç¨ null çè¯ï¼å¯ä»¥ä½¿ç¨ä¸ä¸ªç¹æ®çéæç©ºå¯¹è±¡æ¥ä»£æ¿ nullã
```java
public static final Object NULL = new Object();
```
æåï¼åå享ä¸ä¸ `ConcurrentHashMap` ä½è
æ¬äºº (Doug Lea)对äºè¿ä¸ªé®é¢çåçï¼
> 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.
ç¿»è¯è¿æ¥ä¹åçï¼å¤§è´ææè¿æ¯å线ç¨ä¸å¯ä»¥å®¹å¿æ§ä¹ï¼èå¤çº¿ç¨ä¸æ æ³å®¹å¿ã
### âï¸ConcurrentHashMap è½ä¿è¯å¤åæä½çååæ§åï¼
`ConcurrentHashMap` æ¯çº¿ç¨å®å
¨çï¼æå³çå®å¯ä»¥ä¿è¯å¤ä¸ªçº¿ç¨åæ¶å¯¹å®è¿è¡è¯»åæä½æ¶ï¼ä¸ä¼åºç°æ°æ®ä¸ä¸è´çæ
åµï¼ä¹ä¸ä¼å¯¼è´ JDK1.7 åä¹åçæ¬ç `HashMap` å¤çº¿ç¨æä½å¯¼è´æ»å¾ªç¯é®é¢ã使¯ï¼è¿å¹¶ä¸æå³çå®å¯ä»¥ä¿è¯ææçå¤åæä½é½æ¯ååæ§çï¼ä¸å®ä¸è¦ææ··äºï¼
å¤åæä½æ¯æç±å¤ä¸ªåºæ¬æä½(å¦`put`ã`get`ã`remove`ã`containsKey`ç)ç»æçæä½ï¼ä¾å¦å
夿æä¸ªé®æ¯å¦åå¨`containsKey(key)`ï¼ç¶åæ ¹æ®ç»æè¿è¡æå
¥ææ´æ°`put(key, value)`ãè¿ç§æä½å¨æ§è¡è¿ç¨ä¸å¯è½ä¼è¢«å
¶ä»çº¿ç¨ææï¼å¯¼è´ç»æä¸ç¬¦å颿ã
ä¾å¦ï¼æä¸¤ä¸ªçº¿ç¨ A å B 忶坹 `ConcurrentHashMap` è¿è¡å¤åæä½ï¼å¦ä¸ï¼
```java
// çº¿ç¨ A
if (!map.containsKey(key)) {
map.put(key, value);
}
// çº¿ç¨ B
if (!map.containsKey(key)) {
map.put(key, anotherValue);
}
```
å¦æçº¿ç¨ A å B çæ§è¡é¡ºåºæ¯è¿æ ·ï¼
1. çº¿ç¨ A 夿 map ä¸ä¸åå¨ key
2. çº¿ç¨ B 夿 map ä¸ä¸åå¨ key
3. çº¿ç¨ B å° (key, anotherValue) æå
¥ map
4. çº¿ç¨ A å° (key, value) æå
¥ map
é£ä¹æç»çç»ææ¯ (key, value)ï¼è䏿¯é¢æç (key, anotherValue)ãè¿å°±æ¯å¤åæä½çéå忧坼è´çé®é¢ã
**é£å¦ä½ä¿è¯ `ConcurrentHashMap` å¤åæä½çååæ§å¢ï¼**
`ConcurrentHashMap` æä¾äºä¸äºååæ§çå¤åæä½ï¼å¦ `putIfAbsent`ã`compute`ã`computeIfAbsent` ã`computeIfPresent`ã`merge`çãè¿äºæ¹æ³é½å¯ä»¥æ¥åä¸ä¸ªå½æ°ä½ä¸ºåæ°ï¼æ ¹æ®ç»å®ç key å value æ¥è®¡ç®ä¸ä¸ªæ°ç valueï¼å¹¶ä¸å°å
¶æ´æ°å° map ä¸ã
ä¸é¢ç代ç å¯ä»¥æ¹å为ï¼
```java
// çº¿ç¨ A
map.putIfAbsent(key, value);
// çº¿ç¨ B
map.putIfAbsent(key, anotherValue);
```
æè
ï¼
```java
// çº¿ç¨ A
map.computeIfAbsent(key, k -> value);
// çº¿ç¨ B
map.computeIfAbsent(key, k -> anotherValue);
```
å¾å¤åå¦å¯è½ä¼è¯´äºï¼è¿ç§æ
åµä¹è½å é忥åï¼ç¡®å®å¯ä»¥ï¼ä½ä¸å»ºè®®ä½¿ç¨å éç忥æºå¶ï¼è¿èäºä½¿ç¨ `ConcurrentHashMap` çåè¡·ãå¨ä½¿ç¨ `ConcurrentHashMap` çæ¶åï¼å°½é使ç¨è¿äºååæ§çå¤åæä½æ¹æ³æ¥ä¿è¯ååæ§ã