ConcurrentHashMap์€ ์–ด๋–ป๊ฒŒ ๋™์‹œ์„ฑ์„ ๋ณด์žฅํ• ๊นŒ?

2024. 10. 28. 22:25ยทJava

๋“ค์–ด๊ฐ€๊ธฐ ์•ž์„œ

ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ์ค‘ ๋„์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ํฌ๋กค๋งํ•˜์—ฌ 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์˜ ๋™์ž‘ ๋ฐฉ์‹

  1. ์“ฐ๋ ˆ๋“œ๊ฐ€ ํŠน์ • ๋ฉ”๋ชจ๋ฆฌ ์œ„์น˜์˜ ๊ฐ’์„ ์ฝ๊ณ , ์ด๋ฅผ ๊ธฐ๋Œ€ ๊ฐ’์œผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. 
  2. ์“ฐ๋ ˆ๋“œ๋Š” CAS ์—ฐ์‚ฐ์„ ํ˜ธ์ถœํ•˜๋ฉด์„œ ๊ธฐ๋Œ€ ๊ฐ’๊ณผ ์ƒˆ๋กœ ์„ค์ •ํ•˜๋ ค๋Š” ๊ฐ’์„ ํ•จ๊ป˜ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  3. 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() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ์˜ ์ „์ฒด ๋™์ž‘ ๊ณผ์ •์ž…๋‹ˆ๋‹ค. 

๋™์ผํ•œ ํ‚ค๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ

  1. ์ž…๋ ฅ๋ฐ›์€ ํ‚ค์™€ ๊ฐ’์ด null์ธ์ง€ ํ™•์ธํ•˜๊ณ  null์ผ ๊ฒฝ์šฐ NullPointerException์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ž…๋ ฅ๋ฐ›์€ ํ‚ค์˜ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ , ์ด๋ฅผ spread() ๋ฉ”์„œ๋“œ๋กœ ๋ถ„์‚ฐ์‹œ์ผœ ํ•ด์‹œ ํ…Œ์ด๋ธ”์˜ ์ธ๋ฑ์Šค๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค. 
  3. ํ…Œ์ด๋ธ”์ด ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ๊ธธ์ด๊ฐ€ 0์ด๋ฉด initTable() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
  4. ๊ณ„์‚ฐ๋œ ์ธ๋ฑ์Šค ์œ„์น˜์— ์žˆ๋Š” ๋ฒ„ํ‚ท์ด ๋น„์–ด์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  5. ๋ฒ„ํ‚ท์— ๋™์ผํ•œ ํ‚ค๋กœ ์ €์žฅ๋œ ๋…ธ๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด, ๊ธฐ์กด ๊ฐ’์„ ์ƒˆ๋กœ์šด ๊ฐ’์œผ๋กœ ๋ฎ์–ด์“ฐ๊ณ  ๊ธฐ์กด ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. 

๋™์ผํ•œ ํ‚ค๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ

  1. ์ž…๋ ฅ๋ฐ›์€ ํ‚ค์™€ ๊ฐ’์ด null์ธ์ง€ ํ™•์ธํ•˜๊ณ  null์ผ ๊ฒฝ์šฐ NullPointerException์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  2. ์ž…๋ ฅ๋ฐ›์€ ํ‚ค์˜ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ , ์ด๋ฅผ spread() ๋ฉ”์„œ๋“œ๋กœ ๋ถ„์‚ฐ์‹œ์ผœ ํ•ด์‹œ ํ…Œ์ด๋ธ”์˜ ์ธ๋ฑ์Šค๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค. 
  3. ํ…Œ์ด๋ธ”์ด ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ๊ธธ์ด๊ฐ€ 0์ด๋ฉด initTable() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
  4. ๊ณ„์‚ฐ๋œ ์ธ๋ฑ์Šค ์œ„์น˜์— ์žˆ๋Š” ๋ฒ„ํ‚ท์ด ๋น„์–ด์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  5. ๋ฒ„ํ‚ท์ด ๋น„์–ด์žˆ์„ ๊ฒฝ์šฐ, CAS ์—ฐ์‚ฐ์„ ์‚ฌ์šฉํ•ด ์›์ž์ ์œผ๋กœ ์ƒˆ๋กœ์šด ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. 
  6. ๋…ธ๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด ๋ฐ˜๋ณต๋ฌธ์„ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.

'Java' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Call by Value์™€ Call by Reference  (0) 2025.03.07
Java์˜ GC  (0) 2025.03.02
CompletableFuture์™€ ForkJoinPool  (0) 2024.08.08
'Java' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • Call by Value์™€ Call by Reference
  • Java์˜ GC
  • CompletableFuture์™€ ForkJoinPool
jwooo๐ŸŒฑ
jwooo๐ŸŒฑ
jwooo's log ์ž…๋‹ˆ๋‹ค.
  • jwooo๐ŸŒฑ
    jwooo's log
    jwooo๐ŸŒฑ
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (11)
      • Java (4)
      • Project (5)
      • Computer Science (2)
        • Network (1)
        • Security (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.3
jwooo๐ŸŒฑ
ConcurrentHashMap์€ ์–ด๋–ป๊ฒŒ ๋™์‹œ์„ฑ์„ ๋ณด์žฅํ• ๊นŒ?
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”