멀티스레드 환경에서 여러 스레드가 동시에 하나의 컬렉션에 접근하면 데이터 불일치나 ConcurrentModificationException 같은 문제가 발생할 수 있습니다. Java에서는 java.util 패키지의 Collections 클래스가 제공하는 동기화 메서드를 사용해 컬렉션을 손쉽게 스레드 세이프하게 만들 수 있습니다.
Collections 클래스는 컬렉션 전용으로 동작하는 다양한 유틸리티 메서드를 제공하며, 그중 동기화 관련 메서드들은 다형적 알고리즘(polymorphic algorithms)을 기반으로 각 컬렉션 타입에 맞는 스레드 세이프 래퍼(wrapper)를 반환합니다.
Collections 클래스의 주요 동기화 메서드
| 번호 | 메서드 및 설명 |
|---|---|
| 1 | static <T> Collection<T> synchronizedCollection(Collection<T> c) 컬렉션 객체를 매개변수로 받아, 지정된 컬렉션을 기반으로 하는 동기화(스레드 세이프) 컬렉션을 반환합니다. |
| 2 | static <T> List<T> synchronizedList(List<T> list) List 인터페이스의 객체를 받아, 지정된 리스트를 기반으로 하는 동기화(스레드 세이프) 리스트를 반환합니다. |
| 3 | static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) Map 인터페이스의 객체를 받아, 지정된 맵을 기반으로 하는 동기화(스레드 세이프) 맵을 반환합니다. |
| 4 | static <T> Set<T> synchronizedSet(Set<T> s) Set 인터페이스의 객체를 받아, 지정된 셋을 기반으로 하는 동기화(스레드 세이프) 셋을 반환합니다. |
| 5 | static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m) SortedMap 객체를 받아, 지정된 정렬 맵을 기반으로 하는 동기화(스레드 세이프) 정렬 맵을 반환합니다. |
| 6 | static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s) SortedSet 객체를 받아, 지정된 정렬 셋을 기반으로 하는 동기화(스레드 세이프) 정렬 셋을 반환합니다. |
예제 코드
다음 예제에서는 Vector 객체를 생성한 뒤, Collections.synchronizedCollection() 메서드를 사용하여 스레드 세이프한 컬렉션으로 변환하는 과정을 보여줍니다.
import java.util.Collection;
import java.util.Collections;
import java.util.Vector;
public class CollectionSynchronizedExample {
public static void main(String[] args) {
// Vector 객체 생성
Vector<String> vector = new Vector<String>();
vector.add("JavaFx");
vector.add("Java");
vector.add("WebGL");
vector.add("OpenCV");
System.out.println(vector);
// 동기화(스레드 세이프) 컬렉션으로 변환
Collection<String> synchronizedVector = Collections.synchronizedCollection(vector);
System.out.println("Synchronized " + synchronizedVector);
synchronizedVector.add("CoffeeScript");
}
}실행 결과
[JavaFx, Java, WebGL, OpenCV] Synchronized [JavaFx, Java, WebGL, OpenCV]
주의 사항
동기화된 컬렉션을 사용하더라도 반복(iteration) 중에는 별도의 수동 동기화가 필요합니다. 반복문을 사용할 때는 반드시 컬렉션 자체에 대해 synchronized 블록으로 감싸야 안전합니다.
synchronized (synchronizedVector) {
for (String item : synchronizedVector) {
System.out.println(item);
}
}또한, Java 5 이상에서는 java.util.concurrent 패키지의 CopyOnWriteArrayList, ConcurrentHashMap 등 동시성 컬렉션을 사용하는 것이 성능 면에서 더 유리할 수 있으므로, 상황에 맞게 선택하는 것이 좋습니다.