Spring에서 HashMap을 저장소로 사용할 때 동시성 문제를 고려하는 것은 중요합니다.
HashMap은 Java의 key-value(키-값) 쌍을 저장하는 자료구조로, java.util 패키지에 포함된 해시 테이블 기반의 맵이고, 동기화되지 않은 자료구조입니다.
public class MemoryMemberRepository implements MemberRepository{
// DB 확정이 되지 않아서 Memory용 test용으로만 사용
private static Map<Long, Member> store = new HashMap<>();
// 동시성 문제를 고려한다면 ConcurrentHashMap<>() 을 사용해야 한다.
1. HashMap과 동시성 문제
HashMap은 동기화되지 않은 자료구조이므로, 멀티스레드 환경에서 사용하면 데이터 손실이나 충돌이 발생할 수 있습니다.
예를 들어, 두 개 이상의 스레드가 store.put(key, value)를 동시에 실행할 경우
- 한 스레드가 데이터를 추가하는 동안 다른 스레드가 데이터를 덮어쓸 가능성이 있음
- 한 스레드가 데이터를 읽으면서 다른 스레드가 데이터를 수정하면 읽기 도중 데이터 불일치 문제가 발생할 수 있음
- 결국, 일관성이 깨지고 예기치 않은 버그가 발생할 수 있음
2. ConcurrentHashMap vs. Collections.synchronizedMap()
멀티스레드 환경에서 HashMap을 안전하게 사용하려면 아래 두 가지 방법을 고려할 수 있습니다.
(1) Collections.synchronizedMap()
Map<Long, Member> store = Collections.synchronizedMap(new HashMap<>());
- synchronizedMap()은 맵 전체에 대해 락을 걸어 동기화합니다.
- 단점: 모든 스레드가 put(), get() 등 어떤 작업을 하든 맵 전체를 락으로 보호하므로 성능이 저하됩니다.
- 즉, 한 스레드가 데이터를 추가하거나 읽는 동안 다른 스레드는 대기해야 하므로 경합(Contended Lock)이 심해짐.
(2) ConcurrentHashMap
private static Map<Long, Member> store = new ConcurrentHashMap<>();
- ConcurrentHashMap은 내부적으로 여러 개의 세그먼트(구역)를 나눠서 동기화합니다.
- 즉, 일부 데이터만 접근할 때 해당 영역에만 락을 걸기 때문에 성능이 더 우수합니다.
- 여러 스레드가 동시에 데이터를 읽고 쓸 때도, 필요한 부분에만 락이 걸리므로 synchronizedMap()보다 병렬 처리가 훨씬 효율적입니다.
결론적으로 멀티스레드 환경에서 안전한 HashMap 대체 방법을 정리하면
- 단순한 동기화가 필요할 경우 : Collections.synchronizedMap(new HashMap<>()) -> 비효율적
- 동시성이 중요한 경우 : ConcurrentHashMap<>() -> 효율적
따라서 위 코드에서 동시성을 고려한다면 ConcurrentHashMap<>을 사용하는 것이 적절한 선택입니다.
'개발일지 > Spring' 카테고리의 다른 글
Spring Bean (0) | 2025.02.07 |
---|---|
Spring에서 AppConfig란? (0) | 2025.02.07 |
객체지향원칙을 고려한 Spring 테스트 설계 전략 (JUnit) (0) | 2025.02.06 |
Spring 테스트 케이스 작성 방법과 팁 (JUnit) (2) | 2025.02.06 |
Thymeleaf(타임리프) 템플릿엔진 ? (0) | 2025.02.06 |