어제 오늘 내일

[Java] Collections.synchronizedCollection()으로 아무 컬렉션이나 스레드 안전하게 본문

IT/Java

[Java] Collections.synchronizedCollection()으로 아무 컬렉션이나 스레드 안전하게

hi.anna 2025. 9. 10. 01:59

멀티스레드 환경에서 여러 스레드가 동시에 같은 컬렉션을 수정하면 데이터 불일치ConcurrentModificationException이 발생할 수 있습니다.
이때 Collections.synchronizedCollection()으로 컬렉션을 감싸면 메서드 호출(add/remove 등)을 자동 동기화해 안전하게 사용할 수 있습니다.
이 메서드는 List, Set, Queue임의의 컬렉션을 스레드 안전(Thread-Safe)하게 감싸는 범용 래퍼입니다.

 

1. 기본 사용법

import java.util.*;

public class SyncCollectionExample1 {
    public static void main(String[] args) {
        Collection<String> bag = new ArrayDeque<>();                // 어떤 컬렉션이든 가능
        Collection<String> syncBag = Collections.synchronizedCollection(bag);

        syncBag.add("apple");
        syncBag.add("banana");
        syncBag.add("cherry");

        System.out.println(syncBag);
    }
}

👉 ArrayDeque처럼 전용 동기화 래퍼가 없는 컬렉션도 한 줄로 스레드 안전하게 만들 수 있습니다.

 

2. 반복(iteration) 시 주의: 수동 동기화 필요

메서드 호출은 래퍼가 동기화해 주지만, 반복문은 직접 동기화 블록으로 감싸야 합니다.

import java.util.*;

public class SyncCollectionExample2 {
    public static void main(String[] args) {
        Collection<Integer> base = new ArrayDeque<>();
        Collection<Integer> sync = Collections.synchronizedCollection(base);

        sync.add(1); sync.add(2); sync.add(3);

        // 안전한 반복
        synchronized (sync) {
            for (int n : sync) {
                System.out.println(n);
            }
        }
    }
}

왜? 반복 중에 다른 스레드가 구조를 바꾸면 일관성이 깨질 수 있기 때문입니다.

 

3. 어떤 때 유용한가?

  • 전용 동기화 래퍼가 없는 컬렉션을 쓰는 경우
    (예: ArrayDeque, 특정 라이브러리 컬렉션 등)
  • 컬렉션 타입을 나중에 바꿀 수 있는 인터페이스 설계
    Collection<T>로 노출하고 내부는 필요 시 동기화 래퍼로 교체
  • 간단한 멀티스레드 상황에서 빠르게 안전성 확보

 

4. synchronizedList/Set/Map과의 관계

  • Collections.synchronizedList, synchronizedSet, synchronizedMap해당 타입 전용 래퍼를 제공합니다.
  • synchronizedCollection가장 범용적이며, 리스트/셋/큐 등 아무 컬렉션이나 감쌀 수 있습니다.
  • 공통점: 메서드 자동 동기화, 반복 시 synchronized 블록 필요.

 

5. 동기화 래퍼 vs 동시성 컬렉션(Concurrent Collections)

어떤 것을 써야 할까요?

  • Collections.synchronized* 계열
    • 장점: 간단, 기존 컬렉션을 그대로 감쌈
    • 단점: 전체 메서드에 공유 락 1개 → 경쟁이 많으면 병목 가능
  • 동시성 컬렉션 (ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentLinkedQueue 등)
    • 장점: 경쟁이 많은 환경에서 더 나은 확장성/성능
    • 단점: 동작 특성이 다름(스냅샷 일관성, 약한 일관성 등), 사용법 이해 필요

👉 읽기 많고 쓰기 적음: CopyOnWriteArrayList
👉 키-값 공유, 고경쟁: ConcurrentHashMap
👉 간단·저경쟁: synchronizedCollection도 충분

 

6. 정리

  • Collections.synchronizedCollection(Collection<T> c)
    → 어떤 컬렉션이든 스레드 안전 래퍼로 감싸서 반환
  • 메서드 호출은 자동 동기화, 반복은 synchronized 블록으로 직접 보호
  • 고경쟁/고성능이 필요하면 동시성 컬렉션을 고려

👉 전용 래퍼가 없는 컬렉션을 멀티스레드에서 써야 한다면 Collections.synchronizedCollection()으로 간단히 안전하게!

 

 

반응형
Comments