๋ค์ด๊ฐ๊ธฐ ์์
ํ๋ก์ ํธ ์งํ ์ค ๋์ ๋ฐ์ดํฐ๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ํฌ๋กค๋งํ์ฌ HashMap์ ์ ์ฅํ๋ ๋ก์ง์ ๊ตฌํํ์ต๋๋ค. ๋ชฉํ๋ 100๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์์งํ๋ ๊ฒ์ด์์ผ๋, HashMap์ ์ฌ์ฉํ๋ฉด์ ๋ฐ์ดํฐ ๊ฐ์๊ฐ ์ผ์นํ์ง ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
๋ฌธ์ ์์ธ์ ๋ถ์ํ ๊ฒฐ๊ณผ, ๋น๋๊ธฐ ์์
์์ ๋ฐ์ํ๋ ๋์์ฑ ๋ฌธ์ ๋ก ์ธํด HashMap๋ง์ผ๋ก๋ ๋ฐ์ดํฐ ๊ด๋ฆฌ์ ์ด๋ ค์์ด ์๋ค๋ ์ ์ ์๊ฒ ๋์์ต๋๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด HashMap, HashTable, ConcurrentHashMap์ ์ฐจ์ด์ ์ ์ดํด๋ณด๊ณ , ๊ฐ ์๋ฃ๊ตฌ์กฐ๊ฐ ์ด๋ค ๋ฐฉ์์ผ๋ก ๋์ํ๋์ง ๋น๊ตํด๋ณด๋ ค ํฉ๋๋ค.
HashMap
- key์ value์ null ํ์ฉ
- ๋๊ธฐํ๋ฅผ ๋ณด์ฅํ์ง ์์
HashMap์ ์ค๋ ๋ ์์ (thread-safe)์ ๋ณด์ฅํ์ง ์๊ธฐ ๋๋ฌธ์, ์ฃผ๋ก ์ฑ๊ธ ์ค๋ ๋ ํ๊ฒฝ์์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ ํฉํฉ๋๋ค. ๋๊ธฐํ๋ฅผ ์ฒ๋ฆฌํ์ง ์๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ ํ์ ์๋๊ฐ ๋น ๋ฅด๋ค๋ ์ฅ์ ์ด ์์ง๋ง, ๊ทธ๋งํผ ์ ๋ขฐ์ฑ๊ณผ ์์ ์ฑ ๋ฉด์์๋ ์ ํ์ด ์์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก HashMap์ HashTable์ด๋ ConcurrentHashMap๋ณด๋ค ๋ฐ์ดํฐ ํ์ ์๋๊ฐ ๋น ๋ฅด์ง๋ง, ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์๋ ์ฃผ์๊ฐ ํ์ํ ์๋ฃ๊ตฌ์กฐ์ ๋๋ค.
HashTable
- key์ value์ null์ ํ์ฉํ์ง ์์
- ๋๊ธฐํ ๋ณด์ฅ
HashTable์ ์ค๋ ๋ ์์ (thread-safe)์ ๋ณด์ฅํ๋ฏ๋ก ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ฉ์๋์ synchronized ํค์๋๊ฐ ์ ์ฉ๋์ด ์์ด, ๋ฉ์๋ ํธ์ถ ์ ์ฐ๋ ๋ ๊ฐ ๋๊ธฐํ ๋ฝ์ด ๊ฑธ๋ฆฌ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด ๋๊ธฐํ ๋ฝ ๋๋ถ์ ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์๋ ๋ฐ์ดํฐ์ ๋ฌด๊ฒฐ์ฑ์ด ๋ณด์ฅ๋ฉ๋๋ค. ๊ทธ๋ฌ๋, ๋๊ธฐํ ๋ฝ์ ์๋๋ฅผ ์ ํ์ํฌ ์ ์์ด, ์ฑ๋ฅ ์ธก๋ฉด์์๋ ๋ค์ ๋ถ๋ฆฌํ ์ ์ด ์์ต๋๋ค.
ConcurrentHashMap
- key์ value์ null์ ํ์ฉํ์ง ์์
- ๋๊ธฐํ ๋ณด์ฅ
ConcurrentHashMap์ ์ค๋ ๋ ์์ (thread-safe)์ ๋ณด์ฅํ์ฌ ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ์ฌ์ฉํ ์ ์๋ ์๋ฃ๊ตฌ์กฐ์
๋๋ค. ์ด ๊ตฌํ์ฒด๋ HashMap์ ๋๊ธฐํ ๋ฌธ์ ๋ฅผ ๋ณด์ํ๊ธฐ ์ํด ๊ฐ๋ฐ๋์์ต๋๋ค. ConcurrentHashMap์ ๋๊ธฐํ ์ฒ๋ฆฌ ์, ํน์ ๋
ธ๋(Node)๋ฅผ ์กฐ์ํ ๋ ํด๋น ๋
ธ๋์๋ง ๋ฝ์ ๊ฑฐ๋ ๋ฐฉ์์ผ๋ก ์๋ํฉ๋๋ค. ์ด๋ฅผ ํตํด HashTable๋ณด๋ค ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๋ ์๋๊ฐ ๋น ๋ฅด๊ณ , ์ฑ๋ฅ์ด ํฅ์๋ฉ๋๋ค. ์ฆ, ๋
ธ๋๋ณ๋ก ๊ฐ๋ณ ๋ฝ์ ๊ฑธ์ด ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์๋ ๋์ ํจ์จ์ฑ์ ์ ๊ณตํฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด, ConcurrentHashMap์ด ์ด๋ป๊ฒ ์ด๋ฌํ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ๊ฐ๋ฅํ๋์ง ์์๋ณด๊ธฐ ์ํด ์กฐ๊ธ ๋ ์์ธํ ์์๋ณด๊ฒ ์ต๋๋ค.
ConcurrentHashMap.putVal()
putVal() ๋ฉ์๋๋ ํด๋น ์๋ฃ๊ตฌ์กฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์
ํ ๋ ์คํ๋๋ ๋ฉ์๋๋ก ์ด ๋ฉ์๋๋ ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๊ฐ์ ํค์ ์ฐ๊ธฐ๋ฅผ ์๋ํ ๋ ๋์์ฑ ์ ์ด๋ฅผ ํตํด ์์ ํ๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ฝ์
ํ๊ฑฐ๋ ์
๋ฐ์ดํธํ ์ ์๋๋ก ์ค๊ณ๋์ด ์์ต๋๋ค. ๋ฐ๋ผ์ putVal ๋ฉ์๋๋ฅผ ์์ธํ ์ดํด๋ณด๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์ด ๋ฉ์๋๋ Lock, CAS(Compare-And-Swap) ์ฐ์ฐ, ๋
ธ๋ ๋๊ธฐํ ๋ฑ์ ๊ธฐ๋ฒ์ ํ์ฉํ์ฌ ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์๋ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ๊ณผ ์์ ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
putVal() ๋ฉ์๋์ ํธ์ถ
public V put(K key, V value) {
return putVal(key, value, false);
}
public V putIfAbsent(K key, V value) {
return putVal(key, value, true);
}
final V putVal(K key, V value, boolean onlyifAbsent) {
...
}
์ ๋ ๋ฉ์๋๋ ๋ด๋ถ์ ์ผ๋ก putVal ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค.
๋ฉ์๋๊ฐ ๋ ๊ฐ๋ก ๋๋์ด์ ธ ์๋ ์ด์ ๋ ์ฌ์ฉ ๋ชฉ์ ์ด ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๋๋ค. put ๋ฉ์๋๋ ๊ธฐ์กด์ ๊ฐ์ ๋ฎ์ด์ฐ๊ณ ์๋ก์ด ๊ฐ์ผ๋ก ์ ๋ฐ์ดํธํ ๋ ์ฌ์ฉ๋๋ ๋ฐ๋ฉด, putIfAbsent๋ ํค๊ฐ ์กด์ฌํ์ง ์์ ๋๋ง ๊ฐ์ ์ฝ์ ํ๊ณ , ํค๊ฐ ์ด๋ฏธ ์กด์ฌํ๋ ๊ฒฝ์ฐ ๊ธฐ์กด ๊ฐ์ ๊ทธ๋๋ก ์ ์งํ๋ ๋ก์ง์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ด๋ฌํ ๋ชฉ์ ์ ๋ฐ๋ผ ๋ ๋ฉ์๋๊ฐ ๊ตฌ๋ถ๋์ด ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
CAS (Compare-And-Swap)
ConcurrentHashMap์์ ์ฌ์ฉํ๋ CAS ๊ธฐ๋ฒ์ ๋น๋๊ธฐ ๋์์ฑ ์ ์ด ๋ฐฉ๋ฒ ์ค ํ๋๋ก, ์ฌ๋ฌ ์ฐ๋ ๋๊ฐ ๋์์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๋ ค ํ ๋ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ๋ณด์ฅํฉ๋๋ค. CAS๋ ํ๋์จ์ด ์์ค์์ ์ํ๋๋ ์์์ ์ฐ์ฐ์ผ๋ก, ๊ณต์ ๋ณ์์ ํ์ฌ ๊ฐ์ ๊ธฐ๋ํ ๊ฐ๊ณผ ๋น๊ตํ์ฌ, ๊ธฐ๋ํ ๊ฐ์ด ์ผ์นํ๋ ๊ฒฝ์ฐ์๋ง ์๋ก์ด ๊ฐ์ผ๋ก ๋ณ๊ฒฝํ๋ ๊ณผ์ ์ ํตํด ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค.
CAS๋ ๋ํ ๋ฝ์ ์ฌ์ฉํ์ง ์์ผ๋ฏ๋ก ๋ฐ๋๋ฝ๊ณผ ๊ฐ์ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ๋ฉด์๋ ๋์ ์ฑ๋ฅ์ ์ ์งํ ์ ์์ผ๋ฉฐ, ์ด๋ฌํ ํน์ฑ ๋๋ถ์ ๋ฉํฐ ์ฐ๋ ๋ ํ๊ฒฝ์์๋ ์ฑ๋ฅ ์ ํ ์์ด ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ์ ์งํ๋๋ฐ ํจ๊ณผ์ ์ ๋๋ค.
CAS์ ๋์ ๋ฐฉ์
- ์ฐ๋ ๋๊ฐ ํน์ ๋ฉ๋ชจ๋ฆฌ ์์น์ ๊ฐ์ ์ฝ๊ณ , ์ด๋ฅผ ๊ธฐ๋ ๊ฐ์ผ๋ก ์ ์ฅํฉ๋๋ค.
- ์ฐ๋ ๋๋ CAS ์ฐ์ฐ์ ํธ์ถํ๋ฉด์ ๊ธฐ๋ ๊ฐ๊ณผ ์๋ก ์ค์ ํ๋ ค๋ ๊ฐ์ ํจ๊ป ์ ๋ฌํฉ๋๋ค.
- CAS ์ฐ์ฐ์ด ํธ์ถ๋๋ฉด, ๋ฉ๋ชจ๋ฆฌ์ ํ์ฌ ๊ฐ๊ณผ ๊ธฐ๋ ๊ฐ์ ๋น๊ตํฉ๋๋ค.
- ๋ง์ฝ ํ์ฌ ๊ฐ์ด ๊ธฐ๋ ๊ฐ๊ณผ ์ผ์นํ๋ค๋ฉด, ์ด๋ ํด๋น ๋ฉ๋ชจ๋ฆฌ ์์น์ ๊ฐ์ด ๋ค๋ฅธ ์ฐ๋ ๋์ ์ํด ๋ณ๊ฒฝ๋์ง ์์๋ค๋ ๋ป์ด๋ฏ๋ก, ์์์ ์ผ๋ก ์๋ก์ด ๊ฐ์ผ๋ก ๊ต์ฒดํฉ๋๋ค.
- ๋ง์ฝ ํ์ฌ ๊ฐ์ด ๊ธฐ๋ ๊ฐ๊ณผ ๋ค๋ฅด๋ค๋ฉด, ์ฐ๋ ๋๊ฐ ๊ฐ์ ๋ณ๊ฒฝํ ๊ฒ์ด๋ฏ๋ก, ๊ต์ฒด๋ ์คํจํ๊ณ ์ฐ๋ ๋๋ ํ์ํ ์ฌ์๋๋ฅผ ์ํํ๊ฑฐ๋ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌ๋ฅผ ์งํํฉ๋๋ค.
์ด ๊ณผ์ ์ ํตํด CAS๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ๋ฉด ์ด๋ค ์ฐ๋ ๋๋ ํ๋ก์ธ์ค๋ ๊ฐ์ ํ ์ ์๊ฒ ๋ณดํธ๋๋ฏ๋ก, CAS ์ฐ์ฐ์ ํญ์ ์์ ํ๊ฒ ์ํ๋๊ฑฐ๋ ์ ํ ์ํ๋์ง ์๋ ๋ ๊ฐ์ง ์ํ ์ค ํ๋๋ง ๊ฐ์ง ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์์ต๋๋ค.
โCAS์ ํ๊ณ์
CAS๋ ๋ฉ๋ชจ๋ฆฌ ๊ฐ์ด ๋ณ๊ฒฝ๋์๋์ง ํ์ธํ์ง๋ง, ๊ทธ ๊ฐ์ด ์ค๊ฐ์ ๋ณ๊ฒฝ๋์๋ค๊ฐ ๋ค์ ์๋ ๊ฐ์ผ๋ก ๋์์ค๋ ์ํฉ์ ์ฒ๋ฆฌํ์ง ๋ชปํฉ๋๋ค. ์ด๋ฅผ ABA ๋ฌธ์ ๋ผ๊ณ ํฉ๋๋ค.
putVal() ๋ฉ์๋ ๋ถ์
1. ์ ๋ ฅ ๊ฐ ๊ฒ์ฆ ๋ฐ ํด์ ๊ณ์ฐ
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
- ์ ๋ ฅ ๊ฐ ๊ฒ์ฆ: ConcurrentHashMap์ ํค์ ๊ฐ์ null์ ํ์ฉํ์ง ์๊ธฐ ๋๋ฌธ์ NullPointerException์ ๋ฆฌํดํ๋๋ก ์ค๊ณ๋์ด ์์ต๋๋ค.
- ํด์ ๊ณ์ฐ: key.hashCode()๋ฅผ ํธ์ถํ์ฌ ํด์ ์ฝ๋๋ฅผ ๊ฐ์ ธ์ค๊ณ , spread() ๋ฉ์๋๋ฅผ ํตํด ํด์๋ฅผ ๋ ๊ท ๋ฑํ๊ฒ ๋ถ์ฐ์ํต๋๋ค. ์ด ๊ณผ์ ์ ํด์ ์ถฉ๋์ ์ค์ฌ ํด์ ํ ์ด๋ธ์ ์ฑ๋ฅ์ ์ต์ ํํ๊ธฐ ์ํจ์ ๋๋ค.
2. ๋ฌดํ ๋ฃจํ์ ํ ์ด๋ธ ์ด๊ธฐํ
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = =0;
for (Node<K,V>[] tab = table; ; ) {
if (tab == null || (n = tab.length) == 0)
tab = initTable();
...
}
- ๋ฌดํ ๋ฃจํ ์ค์ : ์ด ๋ฐ๋ณต๋ฌธ์์๋ for๋ฌธ์ ์กฐ๊ฑด์ ์๋ตํ์ฌ ๋ฌดํ ๋ฃจํ๋ฅผ ์์ฑํฉ๋๋ค. ์ด๋ ํน์ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋ ๋๊น์ง ๋ฐ๋ณตํ๊ธฐ ์ํ ๊ฒ์ผ๋ก, ๋ฐ๋ณต ์ข ๋ฃ๋ ๋ฃจํ ๋ด์์ ๋ช ์์ ์ผ๋ก break๊ฐ ํธ์ถ๋ ๋๋ง ์ด๋ฃจ์ด์ง๋๋ค.
- ํ ์ด๋ธ ์ด๊ธฐํ ํ์ธ: ํด์ ํ ์ด๋ธ tab์ด ์ด๊ธฐํ๋์ง ์์๊ฑฐ๋ ๊ธธ์ด๊ฐ 0์ธ ๊ฒฝ์ฐ, initTable() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ด๊ธฐํํฉ๋๋ค.
3. ๋น์ด์๋ ๋ฒํท์ ๋ ธ๋ ์ถ๊ฐ (CAS ์ฐ์ฐ)
for (Node<K,V>[] tab = table; ; ) {
if (tab == null || (n = tab.length == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null, new Node<K, V>(hash, key, value)))
break;
}
}
- ๋ฒํท ๊ฒ์ฌ: ๊ณ์ฐ๋ ์ธ๋ฑ์ค i์ ์๋ ๋ฒํท์ด ๋น์ด์๋์ง ํ์ธํฉ๋๋ค. ๋น์ด์๋ค๋ฉด tabAt() ๋ฉ์๋๋ฅผ ํตํด ํด๋น ์์น์ ๊ฐ์ ๊ฐ์ ธ์ต๋๋ค.
- CAS ์ฐ์ฐ์ ํตํ ๋ ธ๋ ์ถ๊ฐ: ๋ฒํท์ด ๋น์ด์์ ๊ฒฝ์ฐ casTabAt() ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ์์์ ์ผ๋ก ์๋ก์ด ๋ ธ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค. CAS๊ฐ ์ฑ๊ณตํ๋ฉด ๋ ธ๋๊ฐ ์ถ๊ฐ๋ ๊ฒ์ด๋ฏ๋ก, break๋ก ๋ฐ๋ณต๋ฌธ์ ์ข ๋ฃํฉ๋๋ค.
4. ๋ฆฌ์ฌ์ด์ง ์ํ ํ์ธ ๋ฐ ์ง์
for (Mode<K,V>[] tab = table; ; ) {
...
else if ((fh = f.hash) == MOVED) {
tab = helpTransfer(tab, f);
}
}
- ๋ฆฌ์ฌ์ด์ง ์ํ ํ์ธ: f.hash๊ฐ์ด MOVED๋ผ๋ฉด, ํ ์ด๋ธ์ด ํ์ฌ ๋ฆฌ์ฌ์ด์ง ์ค์์ ๋ํ๋ ๋๋ค. ๋ฆฌ์ฌ์ด์ง์ ํด์ ํ ์ด๋ธ์ด ํน์ ์๊ณ์น์ ๋๋ฌํ์ฌ ํฌ๊ธฐ๋ฅผ ํ์ฅํด์ผ ํ ๋ ๋ฐ์ํฉ๋๋ค.
- ๋ฆฌ์ฌ์ด์ง ์ง์: helpTransfer() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ํ์ฌ ์ฐ๋ ๋๊ฐ ๋ฆฌ์ฌ์ด์ง ์์ ์ ์ง์ํ๋๋ก ํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ฌ๋ฌ ์ฐ๋ ๋๊ฐ ๋ณ๋ ฌ๋ก ๋ฆฌ์ฌ์ด์ง์ ์ํํ์ฌ ํ ์ด๋ธ ํฌ๊ธฐ๋ฅผ ํจ์จ์ ์ผ๋ก ์กฐ์ ํ ์ ์์ต๋๋ค.
5. ์กฐ๊ฑด๋ถ๋ก ๊ธฐ์กด ๋ ธ๋ ํ์ธ ๋ฐ ๋ฐํ
for (Mode<K,V>[] tab = table; ; ) {
...
else if ((fh = f.hash) == MOVED) {
tab = helpTransfer(tab, f);
}
else if (onlyIfAbsnet
&& fh == hash
&& ((fk = f.key) == key || (fk != null && key.equals(fk)))
&& (fv = f.val) != null) {
return fv;
}
}
- ์กฐ๊ฑด๋ถ ํ์ธ: onlyIfAbsent๊ฐ true์ธ ๊ฒฝ์ฐ, ํค๊ฐ ์ด๋ฏธ ์กด์ฌํ๋ฉด ๊ฐ์ ๋ณ๊ฒฝํ์ง ์์ผ๋ฏ๋ก ์ฒซ ๋ฒ์งธ ๋ ธ๋๋ฅผ ๋ฝ ์์ด ํ์ธํฉ๋๋ค.
- ๊ธฐ์กด ๊ฐ ๋ฐํ: ํค๊ฐ ์ด๋ฏธ ์กด์ฌํ๊ณ ๊ฐ์ด null์ด ์๋ ๊ฒฝ์ฐ, ๊ธฐ์กด ๊ฐ์ ๋ฐํํ๋ฉฐ ๋ฉ์๋๋ฅผ ์ข ๋ฃํฉ๋๋ค.
6. ๋ฝ์ ์ฌ์ฉํ ๋ ธ๋ ์ฝ์ ๋ฐ ์ ๋ฐ์ดํธ
for (Mode<K,V>[] tab = table; ; ) {
...
else if (onlyIfAbsnet
&& fh == hash
&& ((fk = f.key) == key || (fk != null && key.equals(fk)))
&& (fv = f.val) != null) {
return fv;
}
else {
V oldVal = null;
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f; ; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key, value);
break;
}
}
}
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
else if (f instanceof ReservationNode)
throw new IllegalStateException("Recursive update");
}
}
...
}
- ๋ฝ์ ์ฌ์ฉํ ๋๊ธฐํ: ๋ฒํท์ ์ฒซ ๋ฒ์งธ ๋ ธ๋๊ฐ ์กด์ฌํ๋ฉด ํด๋น ๋ ธ๋๋ฅผ synchronized ๋ธ๋ก์ผ๋ก ๊ฐ์ธ ๋๊ธฐํํฉ๋๋ค. ์ด๋ ์ฌ๋ฌ ์ฐ๋ ๋๊ฐ ๋์์ ๊ฐ์ ๋ฒํท์ ์ ๊ทผํ ๋ ๋ฐ์ํ ์ ์๋ ์ถฉ๋๊ณผ ๋ฐ์ดํฐ ์์์ ๋ฐฉ์งํ๊ธฐ ์ํจ์ ๋๋ค.
- ์ฐ๊ฒฐ ๋ฆฌ์คํธ ์ฒ๋ฆฌ: ๋ฒํท์ด ์ฐ๊ฒฐ ๋ฆฌ์คํธ ๊ตฌ์กฐ๋ก ๋์ด ์๋ ๊ฒฝ์ฐ, ๋ฆฌ์คํธ์ ๊ฐ ๋ ธ๋๋ฅผ ์ํํ๋ฉฐ ๋์ผํ ํค๋ฅผ ์ฐพ์ต๋๋ค. ํค๋ฅผ ๋ฐ๊ฒฌํ๋ฉด ๊ฐ์ ๊ฐฑ์ ํ๊ณ , ์กด์ฌํ์ง ์์ผ๋ฉด ๋ฆฌ์คํธ ๋์ ์๋ก์ด ๋ ธ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
- ํธ๋ฆฌ ๊ตฌ์กฐ ์ฒ๋ฆฌ: ๋ฒํท์ด ํธ๋ฆฌ ๊ตฌ์กฐ์ธ ๊ฒฝ์ฐ, ํธ๋ฆฌ ๋ ธํธ๋ฅผ ํ์ํ์ฌ ๋์ผํ ํค๋ฅผ ์ฐพ์ ๊ฐ์ ์ ๋ฐ์ดํธํ๊ฑฐ๋, ํค๊ฐ ์์ผ๋ฉด ์๋ก์ด ๋ ธ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
7. ํธ๋ฆฌํ ๊ฒ์ฌ
for (Node<K,V>[] tab = table;;) {
// ...
// ์ด์ ์ค๋ช
์ฝ๋ (๊ธธ์ด์ ์๋ต)
else {
V oldVal = null;
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
...
}
}
else if (f instanceof TreeBin) {
...
}
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
- ํธ๋ฆฌํ ๊ฒ์ฌ: ๋ฒํท์ ์๋ ๋ ธ๋์ ์(binCount)๊ฐ TREEIFY_THRESHOLD(๊ธฐ๋ณธ ๊ฐ 8)๋ฅผ ์ด๊ณผํ ๊ฒฝ์ฐ, ์ฐ๊ฒฐ ๋ฆฌ์คํธ๋ฅผ ํธ๋ฆฌ ๊ตฌ์กฐ๋ก ๋ณํํฉ๋๋ค. ์ด๋ ํด์ ์ถฉ๋์ด ๋ง์ ์ํฉ์์ ๊ฒ์ ์ฑ๋ฅ์ ์ต์ ํํ๊ธฐ ์ํจ์ ๋๋ค.
8. ๋ ธ๋ ์ ์ฆ๊ฐ ๋ฐ ์ข ๋ฃ ์ฒ๋ฆฌ
for (Node<K,V>[] tab = table;;) {
...
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
}
addCount(1L, binCount);
return null;
- ๋ ธ๋ ์ ์ฆ๊ฐ: ์๋ก์ด ๋ ธ๋๊ฐ ์ถ๊ฐ๋ ๋๋ง๋ค ํด์๋งต์ ์ ์ฒด ๋ ธ๋ ์๋ฅผ ์ฆ๊ฐ์ํค๋ฉฐ, ํ์ ์ ํ ์ด๋ธ ํฌ๊ธฐ๋ฅผ ์กฐ์ ํ์ฌ ํด์ ์ถฉ๋์ ์ค์ด๊ณ ์ฑ๋ฅ์ ์ต์ ํํฉ๋๋ค.
- ๊ฒฐ๊ณผ ๋ฐํ: ์๋ก์ด ํค-๊ฐ ์์ด ์ฑ๊ณต์ ์ผ๋ก ์ถ๊ฐ๋์์์ ๋ํ๋ด๊ธฐ ์ํด null์ ๋ฐํํฉ๋๋ค.
๋์ ๊ณผ์ ์ด ์ ๋ฆฌ
์๋๋ put() ๋ฉ์๋ ํธ์ถ ์์ ์ ์ฒด ๋์ ๊ณผ์ ์ ๋๋ค.
๋์ผํ ํค๊ฐ ์ด๋ฏธ ์กด์ฌํ๋ ๊ฒฝ์ฐ
- ์ ๋ ฅ๋ฐ์ ํค์ ๊ฐ์ด null์ธ์ง ํ์ธํ๊ณ null์ผ ๊ฒฝ์ฐ NullPointerException์ ๋ฐํํฉ๋๋ค.
- ์ ๋ ฅ๋ฐ์ ํค์ ํด์์ฝ๋๋ฅผ ๊ณ์ฐํ๊ณ , ์ด๋ฅผ spread() ๋ฉ์๋๋ก ๋ถ์ฐ์์ผ ํด์ ํ ์ด๋ธ์ ์ธ๋ฑ์ค๋ฅผ ์ฐพ์ต๋๋ค.
- ํ ์ด๋ธ์ด ์ด๊ธฐํ๋์ง ์์๊ฑฐ๋ ๊ธธ์ด๊ฐ 0์ด๋ฉด initTable() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ด๊ธฐํํฉ๋๋ค.
- ๊ณ์ฐ๋ ์ธ๋ฑ์ค ์์น์ ์๋ ๋ฒํท์ด ๋น์ด์๋์ง ํ์ธํฉ๋๋ค.
- ๋ฒํท์ ๋์ผํ ํค๋ก ์ ์ฅ๋ ๋ ธ๋๊ฐ ์๋ค๋ฉด, ๊ธฐ์กด ๊ฐ์ ์๋ก์ด ๊ฐ์ผ๋ก ๋ฎ์ด์ฐ๊ณ ๊ธฐ์กด ๊ฐ์ ๋ฐํํฉ๋๋ค.
๋์ผํ ํค๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ
- ์ ๋ ฅ๋ฐ์ ํค์ ๊ฐ์ด null์ธ์ง ํ์ธํ๊ณ null์ผ ๊ฒฝ์ฐ NullPointerException์ ๋ฐํํฉ๋๋ค.
- ์ ๋ ฅ๋ฐ์ ํค์ ํด์์ฝ๋๋ฅผ ๊ณ์ฐํ๊ณ , ์ด๋ฅผ spread() ๋ฉ์๋๋ก ๋ถ์ฐ์์ผ ํด์ ํ ์ด๋ธ์ ์ธ๋ฑ์ค๋ฅผ ์ฐพ์ต๋๋ค.
- ํ ์ด๋ธ์ด ์ด๊ธฐํ๋์ง ์์๊ฑฐ๋ ๊ธธ์ด๊ฐ 0์ด๋ฉด initTable() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ด๊ธฐํํฉ๋๋ค.
- ๊ณ์ฐ๋ ์ธ๋ฑ์ค ์์น์ ์๋ ๋ฒํท์ด ๋น์ด์๋์ง ํ์ธํฉ๋๋ค.
- ๋ฒํท์ด ๋น์ด์์ ๊ฒฝ์ฐ, CAS ์ฐ์ฐ์ ์ฌ์ฉํด ์์์ ์ผ๋ก ์๋ก์ด ๋ ธ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
- ๋ ธ๋๊ฐ ์ถ๊ฐ๋๋ฉด ๋ฐ๋ณต๋ฌธ์ ์ข ๋ฃํฉ๋๋ค.
'Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
CompletableFuture์ ForkJoinPool (0) | 2024.08.08 |
---|