Post

๐Ÿ“‘ JAVA 04 - Collection Framework์™€ HashMap ๋‚ด๋ถ€ ๊ตฌ์กฐ

๐Ÿ“‘ JAVA 04 - Collection Framework์™€ HashMap ๋‚ด๋ถ€ ๊ตฌ์กฐ

Java Collection Framework์™€ HashMap ๋‚ด๋ถ€ ๊ตฌ์กฐ

ํ•™์Šต ๋ชฉํ‘œ

์ด๋ฒˆ ์ฃผ์ œ์˜ ํ•ต์‹ฌ์€ ๋‹จ์ˆœํžˆ:

โ€œHashMap์€ Key-Value ์ €์žฅ ์ž๋ฃŒ๊ตฌ์กฐโ€

์ˆ˜์ค€์ด ์•„๋‹ˆ๋‹ค.

์‹ค๋ฌด์—์„œ๋Š” ๋‹ค์Œ์„ ์ดํ•ดํ•ด์•ผ ํ•œ๋‹ค.

  • HashMap์€ ์™œ ๋น ๋ฅธ๊ฐ€?

  • collision์€ ์™œ ๋ฐœ์ƒํ•˜๋Š”๊ฐ€?

  • resize๋Š” ์™œ ์œ„ํ—˜ํ•œ๊ฐ€?

  • load factor๋Š” ์™œ ์กด์žฌํ•˜๋Š”๊ฐ€?

  • ConcurrentHashMap์€ ์™œ ํ•„์š”ํ•œ๊ฐ€?

  • CAS๋Š” ์™œ ๋“ฑ์žฅํ–ˆ๋Š”๊ฐ€?

  • ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์–ด๋–ค ์žฅ์• ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”๊ฐ€?

์ฆ‰:

Java Collection ๋‚ด๋ถ€ ๋™์ž‘๊ณผ ๋™์‹œ์„ฑ ์„ค๊ณ„ ์ฒ ํ•™

์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ๋‹ค.


Java Collection Framework ๊ตฌ์กฐ

flowchart TD

    A[Collection]

    A --> B[List]
    A --> C[Set]
    A --> D[Queue]

    E[Map]

    B --> F[ArrayList]
    B --> G[LinkedList]

    C --> H[HashSet]

    E --> I[HashMap]
    E --> J[ConcurrentHashMap]

HashMap ํ•ต์‹ฌ ๊ตฌ์กฐ

HashMap์€ ๋‚ด๋ถ€์ ์œผ๋กœ:

๋ฐฐ์—ด + LinkedList + Tree

๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.


๊ธฐ๋ณธ ๊ตฌ์กฐ

flowchart TD

    A[Bucket Array]

    A --> B[Bucket 0]
    A --> C[Bucket 1]
    A --> D[Bucket 2]

    D --> E[Node]
    E --> F[Node]
    F --> G[Node]

์™œ ๋น ๋ฅธ๊ฐ€?

HashMap ํ•ต์‹ฌ์€:

hash ๊ฐ’์„ ์ด์šฉํ•ด index ์ง์ ‘ ์ ‘๊ทผ

ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์˜ˆ:

1
index = hash(key) % bucketSize

์ฆ‰:

๋ฐฐ์—ด ํƒ์ƒ‰์ฒ˜๋Ÿผ ๋™์ž‘ํ•œ๋‹ค.

ํ‰๊ท  ์‹œ๊ฐ„ ๋ณต์žก๋„:

1
O(1)

collision์ด๋ž€?

์„œ๋กœ ๋‹ค๋ฅธ key๊ฐ€:

๊ฐ™์€ bucket index

๋กœ ๋“ค์–ด๊ฐ€๋Š” ํ˜„์ƒ.

์˜ˆ:

1
2
"A" -> bucket 3
"B" -> bucket 3

์™œ collision์ด ๋ฐœ์ƒํ•˜๋Š”๊ฐ€?

Hash ๊ณต๊ฐ„์€ ์ œํ•œ์ ์ด๋‹ค.

ํ•˜์ง€๋งŒ key๋Š” ๋ฌดํ•œํžˆ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰:

์™„๋ฒฝํ•œ hash๋Š” ํ˜„์‹ค์ ์œผ๋กœ ๋ถˆ๊ฐ€๋Šฅ

ํ•˜๋‹ค.


collision ์ฒ˜๋ฆฌ ๋ฐฉ์‹

JDK 7:

  • LinkedList ์‚ฌ์šฉ

JDK 8 ์ดํ›„:

  • ์ผ์ • ๊ธธ์ด ์ด์ƒ์ด๋ฉด Tree ๋ณ€ํ™˜

JDK8 Tree ๊ตฌ์กฐ ๋„์ž…

flowchart TD

    A[Bucket]
        --> B[Red-Black Tree]

์™œ Tree๋ฅผ ๋„์ž…ํ–ˆ๋Š”๊ฐ€?

LinkedList collision ์‹ฌํ•ด์ง€๋ฉด:

1
O(n)

๊นŒ์ง€ ์„ฑ๋Šฅ ์ €ํ•˜ ๋ฐœ์ƒ.

ํŠนํžˆ ์•…์˜์  hash collision ๊ณต๊ฒฉ ๊ฐ€๋Šฅ.

Tree ์‚ฌ์šฉ ์‹œ:

1
O(log n)

๋ณด์žฅ ๊ฐ€๋Šฅ.


resize๋ž€?

Bucket ํฌ๊ธฐ ์ฆ๊ฐ€ ์ž‘์—….

์˜ˆ:

1
16 โ†’ 32 โ†’ 64

์™œ resize๊ฐ€ ํ•„์š”ํ•œ๊ฐ€?

Bucket์ด ๋ถ€์กฑํ•˜๋ฉด collision ์ฆ๊ฐ€.

์ฆ‰:

์„ฑ๋Šฅ ๊ธ‰๊ฒฉํžˆ ์ €ํ•˜.


load factor๋ž€?

๊ธฐ๋ณธ๊ฐ’:

1
0.75

์˜๋ฏธ:

1
(size / bucket capacity)

์™œ 0.75์ธ๊ฐ€?

Trade-off ๋•Œ๋ฌธ์ด๋‹ค.


load factor ๋‚ฎ์œผ๋ฉด

์žฅ์ :

  • collision ๊ฐ์†Œ

๋‹จ์ :

  • ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„

load factor ๋†’์œผ๋ฉด

์žฅ์ :

  • ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ

๋‹จ์ :

  • collision ์ฆ๊ฐ€

resize๋Š” ์™œ ์œ„ํ—˜ํ•œ๊ฐ€?

resize๋Š”:

๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์žฌ๋ฐฐ์น˜(rehash)

ํ•œ๋‹ค.

flowchart TD

    A[Old Bucket]
        --> B[Rehash]
        --> C[New Bucket]

์ฆ‰:

๋น„์šฉ์ด ๋งค์šฐ ํฌ๋‹ค.


์‹ค๋ฌด์—์„œ ์ค‘์š”ํ•œ ์ด์œ 

๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ insert ์‹œ:

  • CPU spike

  • latency ์ฆ๊ฐ€

  • STW ์ฆ๊ฐ€ ๊ฐ€๋Šฅ

์ฆ‰:

๋Œ€์šฉ๋Ÿ‰ ์„œ๋น„์Šค์—์„œ resize๋Š” ์‹ค์ œ ์„ฑ๋Šฅ ์ด์Šˆ๋‹ค.


HashMap์€ Thread Safeํ•œ๊ฐ€?

์•„๋‹ˆ๋‹ค.

๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค.


์™œ ์œ„ํ—˜ํ•œ๊ฐ€?

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ:

  • ๋™์‹œ put

  • resize ์ถฉ๋Œ

  • ๋ฐ์ดํ„ฐ ์œ ์‹ค

๋ฐœ์ƒ ๊ฐ€๋Šฅ.


๊ณผ๊ฑฐ JDK7 resize ๋ฌธ์ œ

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ resize ์‹œ:

1
2
๋ฌดํ•œ ๋ฃจํ”„
CPU 100%

๋ฌธ์ œ๊ฐ€ ์‹ค์ œ ์žˆ์—ˆ๋‹ค.

์œ ๋ช…ํ•œ ๋ฉด์ ‘ ์งˆ๋ฌธ์ด๋‹ค.


์™œ ๋ฐœ์ƒํ–ˆ๋Š”๊ฐ€?

resize ์ค‘ LinkedList ๋ฐฉํ–ฅ ๊ผฌ์ž„ ๋ฐœ์ƒ.

์ฆ‰:

concurrent modification ๋ฌธ์ œ

์˜€๋‹ค.


synchronized Map ๋ฌธ์ œ

1
Collections.synchronizedMap(map)

๊ฐ€๋Šฅ์€ ํ•˜๋‹ค.

ํ•˜์ง€๋งŒ:

์ „์ฒด lock

์ด๋‹ค.


๋ฌธ์ œ์ 

flowchart TD

    A[Thread 1]
    B[Thread 2]
    C[Thread 3]

    A --> D[Global Lock]
    B --> D
    C --> D

์ฆ‰:

๋™์‹œ์„ฑ ์„ฑ๋Šฅ์ด ๋งค์šฐ ๋–จ์–ด์ง„๋‹ค.


ConcurrentHashMap ๋“ฑ์žฅ

๋ชฉํ‘œ:

Thread Safe + ๋†’์€ ๋™์‹œ์„ฑ


JDK7 ConcurrentHashMap

Segment ๊ธฐ๋ฐ˜.

flowchart TD

    A[ConcurrentHashMap]

    A --> B[Segment 1]
    A --> C[Segment 2]
    A --> D[Segment 3]

Segment๋ณ„ lock ์‚ฌ์šฉ.


JDK8 ConcurrentHashMap

๋” ๋ฐœ์ „ํ–ˆ๋‹ค.

ํ•ต์‹ฌ:

  • CAS

  • synchronized ์ตœ์†Œํ™”

  • bucket ๋‹จ์œ„ locking


CAS๋ž€?

Compare And Swap.

flowchart TD

    A[ํ˜„์žฌ ๊ฐ’ ํ™•์ธ]
        --> B{์˜ˆ์ƒ๊ฐ’ ์ผ์น˜?}

    B -->|YES| C[๊ฐ’ ๋ณ€๊ฒฝ]
    B -->|NO| D[์žฌ์‹œ๋„]

์™œ ์ค‘์š”ํ•œ๊ฐ€?

๊ธฐ์กด lock ๋ฐฉ์‹:

1
Thread Blocking

๋ฐœ์ƒ.

CAS๋Š”:

lock ์—†์ด ์›์ž์  ์—ฐ์‚ฐ ์ˆ˜ํ–‰

๊ฐ€๋Šฅ.


Atomic ํด๋ž˜์Šค๋„ CAS ์‚ฌ์šฉ

์˜ˆ:

1
2
AtomicInteger
AtomicLong

CAS ๋ฌธ์ œ์ 

์™„๋ฒฝํ•˜์ง€ ์•Š๋‹ค.


1. Spin ๋ฌธ์ œ

์‹คํŒจ ์‹œ ๊ณ„์† ์žฌ์‹œ๋„.

CPU ์‚ฌ์šฉ๋Ÿ‰ ์ฆ๊ฐ€ ๊ฐ€๋Šฅ.


2. ABA ๋ฌธ์ œ

๊ฐ’์ด:

1
A โ†’ B โ†’ A

๋ณ€๊ฒฝ๋ผ๋„ ๊ฐ์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์Œ.


ConcurrentHashMap ํ•ต์‹ฌ ์ฒ ํ•™

โ€œlock์„ ์ตœ๋Œ€ํ•œ ์ค„์ธ๋‹คโ€

์ด๋‹ค.

์‹ค๋ฌด์—์„œ๋Š” ์ด๊ฒŒ ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค.


์‹ค๋ฌด ์‚ฌ์šฉ ์‚ฌ๋ก€

๋Œ€ํ‘œ์ ์œผ๋กœ:

  • Cache

  • Session ์ €์žฅ

  • ๋™์‹œ ์š”์ฒญ ์ƒํƒœ ๊ด€๋ฆฌ

  • API Rate Limiting

๋“ฑ์— ๋งŽ์ด ์‚ฌ์šฉ.


์„ฑ๋Šฅ ๊ด€์ 

HashMap:

  • ๋‹จ์ผ Thread ์ตœ๊ณ  ์„ฑ๋Šฅ

ConcurrentHashMap:

  • ๋ฉ€ํ‹ฐ Thread ์ตœ์ ํ™”

์ฆ‰:

์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๋‹ค.


Trade-off

HashMap

์žฅ์ :

  • ๋น ๋ฆ„

  • ๋‹จ์ˆœ

๋‹จ์ :

  • Thread Unsafe

synchronizedMap

์žฅ์ :

  • ๊ตฌํ˜„ ์‰ฌ์›€

๋‹จ์ :

  • ์ „์ฒด lock

ConcurrentHashMap

์žฅ์ :

  • ๋†’์€ ๋™์‹œ์„ฑ

  • lock ์ตœ์†Œํ™”

๋‹จ์ :

  • ๋‚ด๋ถ€ ๊ตฌ์กฐ ๋ณต์žก

  • ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ ์ฆ๊ฐ€ ๊ฐ€๋Šฅ


์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ์‹ค์ˆ˜

1. HashMap์„ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ์—์„œ ์‚ฌ์šฉ

์‹ค๋ฌด ์žฅ์•  ๋งค์šฐ ํ”ํ•จ.


2. resize ๋น„์šฉ ๋ฌด์‹œ

๋Œ€๋Ÿ‰ insert ์‹œ ์œ„ํ—˜.


3. ConcurrentHashMap์ด๋ฉด ๋ฌด์กฐ๊ฑด ์•ˆ์ „ํ•˜๋‹ค๊ณ  ์ฐฉ๊ฐ

๋ณตํ•ฉ ์—ฐ์‚ฐ์€ ์—ฌ์ „ํžˆ ์œ„ํ—˜.

์˜ˆ:

1
2
3
if(map.get(key) == null) {
    map.put(key, value);
}

race condition ๊ฐ€๋Šฅ.


๋ฉด์ ‘ ๊ผฌ๋ฆฌ ์งˆ๋ฌธ

Q1. HashMap์€ ์™œ ๋น ๋ฅธ๊ฐ€?

ํ•ต์‹ฌ:

  • hash ๊ธฐ๋ฐ˜ index ์ ‘๊ทผ

  • ํ‰๊ท  O(1)


Q2. collision์€ ์™œ ๋ฐœ์ƒํ•˜๋Š”๊ฐ€?

ํ•ต์‹ฌ:

  • ์ œํ•œ๋œ bucket ๊ณต๊ฐ„

  • hash ์ถฉ๋Œ ๋ถˆ๊ฐ€ํ”ผ


Q3. JDK8์—์„œ Tree ๊ตฌ์กฐ๋ฅผ ๋„์ž…ํ•œ ์ด์œ ๋Š”?

ํ•ต์‹ฌ:

  • collision ์„ฑ๋Šฅ ๊ฐœ์„ 

  • O(log n) ๋ณด์žฅ


Q4. ConcurrentHashMap์€ ์–ด๋–ป๊ฒŒ ๋™์‹œ์„ฑ์„ ๊ฐœ์„ ํ–ˆ๋Š”๊ฐ€?

ํ•ต์‹ฌ:

  • CAS

  • lock ์ตœ์†Œํ™”

  • bucket ๋‹จ์œ„ ๋™๊ธฐํ™”


Q5. CAS๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

ํ•ต์‹ฌ:

  • lock-free atomic ์—ฐ์‚ฐ

์ข‹์€ ๋‹ต๋ณ€ ์˜ˆ์‹œ

HashMap์€ hash ๊ธฐ๋ฐ˜ bucket index ์ ‘๊ทผ์„ ํ†ตํ•ด ํ‰๊ท  O(1)์˜ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ collision ๋ฌธ์ œ์™€ resize ๋น„์šฉ์ด ์กด์žฌํ•˜๋ฉฐ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋Š” Thread Safeํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ConcurrentHashMap์ด ๋“ฑ์žฅํ–ˆ์œผ๋ฉฐ JDK8 ์ดํ›„์—๋Š” CAS์™€ fine-grained locking์„ ์ด์šฉํ•ด ๋†’์€ ๋™์‹œ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
๋‹ค๋งŒ CAS ์—ญ์‹œ spin๊ณผ ABA ๊ฐ™์€ Trade-off๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.


๊ด€๋ จ CS ๊ฐœ๋… ์—ฐ๊ฒฐ

  • Hash Table

  • Collision Resolution

  • Red-Black Tree

  • Compare-And-Swap

  • Lock-Free Algorithm

  • Race Condition

  • Concurrent Programming


ํ˜„์—…์—์„œ ํŠนํžˆ ์ค‘์š”ํ•œ ํฌ์ธํŠธ

1. HashMap์€ ์ ˆ๋Œ€ Thread Safeํ•˜์ง€ ์•Š๋‹ค

์‹ค๋ฌด ์žฅ์•  ๋งค์šฐ ํ”ํ•˜๋‹ค.


2. resize๋Š” ๋น„์šฉ์ด ํฌ๋‹ค

๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์‹œ ์ค‘์š”.


3. CAS ์ดํ•ด๋Š” ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค

Concurrent ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํ•ต์‹ฌ.


4. ConcurrentHashMap๋„ ์™„๋ฒฝํ•˜์ง€ ์•Š๋‹ค

๋ณตํ•ฉ ์—ฐ์‚ฐ์€ ์—ฌ์ „ํžˆ ์ฃผ์˜ ํ•„์š”.


ํ•ต์‹ฌ ์š”์•ฝ

  • HashMap์€ hash ๊ธฐ๋ฐ˜ ์ž๋ฃŒ๊ตฌ์กฐ๋‹ค

  • collision์€ ํ•„์—ฐ์ ์œผ๋กœ ๋ฐœ์ƒํ•œ๋‹ค

  • JDK8๋ถ€ํ„ฐ Tree ๊ตฌ์กฐ๋กœ ์„ฑ๋Šฅ ๊ฐœ์„ 

  • resize๋Š” ๋งค์šฐ ๋น„์‹ผ ์ž‘์—…์ด๋‹ค

  • HashMap์€ Thread Safeํ•˜์ง€ ์•Š๋‹ค

  • ConcurrentHashMap์€ CAS ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์‹œ์„ฑ์„ ๊ฐœ์„ ํ–ˆ๋‹ค

  • CAS๋„ spin/ABA ๊ฐ™์€ Trade-off๋ฅผ ๊ฐ€์ง„๋‹ค

  • ์‹ค๋ฌด์—์„œ๋Š” ๋™์‹œ์„ฑ ๋ฌธ์ œ ์ดํ•ด๊ฐ€ ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค

This post is licensed under CC BY 4.0 by the author.