티스토리 뷰
오늘은 다중 스레드 환경에서 자주 사용되는 전략인 COW(Copy-On-Write) 를 Java의 CopyOnWriteArrayList 통해 알아보겠습니다.
1. COW란?
COW는 Copy-On-Write의 약자로, 쓰기 작업 시 데이터의 복사본을 만들어 수정 후 원본을 교체하는 전략입니다. 읽기 작업은 기존 데이터를 그대로 사용해 락 없이 빠르고 안전하며 다중 스레드 환경에서 읽기 작업이 많을 때 유용하게 사용됩니다.
아래 흐름도를 통해 간단히 알아보겠습니다.
쓰기 요청
1. 쓰기 요청 시 ReentrantLock을 획득합니다.
2. 이후 기존 배열을 복사하고, 복사본에 요소를 추가/수정 후 원본 배열을 교체합니다.
3. 원본 배열 교체 후, 락을 해제해 쓰기를 완료합니다.
읽기 요청
1. 읽기 요청은 락 없이 배열 스냅샷을 반환해 빠르고 안전합니다.
2. CopyOnWriteArrayList 사용
Java의 CopyOnWriteArrayList는 COW 기법을 사용한 주요 사례입니다. 대표적은 예제들을 통해 간단히 알아보겠습니다.
예제1. 이벤트 리스터
import java.util.concurrent.CopyOnWriteArrayList;
interface Listener {
void onEvent();
}
class MyListener implements Listener {
public void onEvent() { System.out.println("Event triggered!"); }
}
CopyOnWriteArrayList<Listener> listeners = new CopyOnWriteArrayList<>();
listeners.add(new MyListener());
new Thread(() -> listeners.add(new MyListener())).start(); // 다른 스레드에서 리스너 추가
for (Listener l : listeners) { l.onEvent(); } // 스냅샷 기반으로 안전한 순회
- 이 예제는 다중 스레드 환경에서 이벤트 리스너를 관리하는 상황을 보여줍니다. 추가/삭제 중에도 Iterator가 스냅샷을 사용해 안전하게 순회합니다. 쓰기 작업은 배열 복사로 처리되면, 읽기는 락 없이 빠르게 수행됩니다.
예제2. 로그 데이터 처리
import java.util.concurrent.CopyOnWriteArrayList;
CopyOnWriteArrayList<String> logs = new CopyOnWriteArrayList<>();
new Thread(() -> logs.add("Log entry: " + System.currentTimeMillis())).start(); // 스레드1: 로그 추가
new Thread(() -> System.out.println("Current logs: " + logs)).start(); // 스레드2: 로그 읽기
- 이 예제는 다중 스레드 환경에서 로그 데이터를 안전하게 기록하고 조회하는 상황을 보여줍니다. 로그 추가 시 배열 복사본을 만들어 수정하므로, 다른 스레드의 읽기 작업이 중단되지 않습니다. 읽기 작업은 항상 최신 스냅샷을 사용해 빠르고 안전합니다.
3. ArrayList 와 비교
특징 | CopyOnWriteArrayList | ArrayList |
스레드 안전성 | 스레드 안전 (COW 전략) | 비스레드 안전 |
쓰기 동작 | 배열 복사 후 수정, 비용 높음 | 배열 직접 수정, 빠름 |
읽기 동작 | 락 없이 스냅샷 사용, 빠름 | 직접 접근, 빠름 |
사용 사례 | 읽기 중심 다중 스레드 (예, 이벤트 리스너) | 단일 스레드 (예, 로컬 데이터 처리) |
- COW: 스레드 안전, 읽기 성능 우수, 쓰기 시 메모리/성능 오버헤드 -> 읽기 중심 작업에 적합
- ArrayList : 빠른 읽기/쓰기, 메모리 효율적 -> 단일 스레드 환경에 적합
동시성 처리 비교
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
// ArrayList: 동시 수정 시 예외
List<String> arrayList = new ArrayList<>(Arrays.asList("A", "B"));
for (String item : arrayList) { arrayList.remove(item); } // ConcurrentModificationException
// CopyOnWriteArrayList: 안전
CopyOnWriteArrayList<String> cowList = new CopyOnWriteArrayList<>(Arrays.asList("A", "B"));
for (String item : cowList) { cowList.remove(item); } // 스냅샷 기반으로 안전
- ArrayList는 순회 중 요소를 제거하면 ConcurrentModificationException 이 발생합니다. 이는 ArrayList가 비스레드 안전하며, Iterator가 배열의 현재 상태를 추적하기 때문입니다. 반면 CopyOnWriteArrayList는 순회 시 배열의 스냅샷을 사용하므로, 다른 스레드에서 요소를 추가/삭제해도 안전하게 동작합니다. 이는 COW 전략이 쓰기 작업 시 복사본을 만들어 원본을 보호하기 때문입니다.
4. 마무리
COW는 다중 스레드 환경에서 데이터를 안전하고 효율적으로 관리하는 전략입니다. 이벤트 리스너 관리나 로그 처리 같은 시나리오에서 COW의 스레드 안전성을 활용해 안정적인 코드를 작성해볼 수 있습니다.
감사합니다.
'프로그래밍 언어 > Java' 카테고리의 다른 글
[Java] 얕은 복사와 깊은 복사 (2) | 2025.07.26 |
---|---|
[Java] 자바 제네릭과 오버로딩 (2) | 2024.10.24 |
[Java] 소수 판별하기 (1) | 2024.08.21 |
[Java] 우선순위큐(PriorityQueue) 사용 방법 (1) | 2024.07.23 |
[Java] The type com.fasterxml.jackson.core.JsonProcessingException cannot be resolved. It is indirectly referenced from required .class files (1) | 2024.07.02 |
최근에 올라온 글
- Total
- Today
- Yesterday