Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

Java ArrayList vs CopyOnWriteArrayList: 핵심 차이점 완벽 비교

Java에서 ArrayListCopyOnWriteArrayList는 모두 List 인터페이스를 구현한 대표적인 클래스입니다. 하지만 내부 동작 방식과 설계 목적이 다르기 때문에 여러 중요한 차이점을 가지고 있습니다.

아래 표는 두 클래스의 주요 차이점을 항목별로 정리한 것입니다.

ArrayList와 CopyOnWriteArrayList의 주요 차이점

번호구분ArrayListCopyOnWriteArrayList
1동기화(Synchronization)기본적으로 동기화되지 않습니다(non-synchronized).동기화되어 있어 한 번에 하나의 스레드만 객체에 접근할 수 있습니다.
2성능(Performance)동기화 오버헤드가 없어 처리 속도가 빠릅니다.동기화 및 복사 작업으로 인해 성능이 상대적으로 느립니다.
3Fail-fast / Fail-safe반복자(Iterator)가 fail-fast 방식으로 동작하며, 순회 중 컬렉션이 수정되면 ConcurrentModificationException이 발생합니다.fail-safe 방식으로 동작하며, 순회 중에도 컬렉션의 수정이 허용됩니다.
4요소 제거(Remove)반복(iteration) 중에도 반복자를 통해 remove() 연산을 수행할 수 있습니다.반복 중에는 remove() 연산을 수행할 수 없으며, 시도할 경우 런타임 예외인 UnsupportedOperationException이 발생합니다.
5도입 시기Java 1.2 버전부터 제공된 오래된 클래스입니다.Java 5(버전 1.5)에서 추가된 비교적 최신 클래스입니다.
6패키지(Package)java.util 패키지에 포함되어 있습니다.java.util.concurrent 패키지에 포함되어 있습니다.

예제 1: ArrayList 사용 예시

다음 예제는 ArrayList의 반복자를 사용해 순회 중에 요소를 안전하게 제거하는 코드입니다.

import java.util.*;

public class ArrayListDemo {
    public static void main(String[] args) {
        ArrayList<String> l = new ArrayList<>();
        l.add("A");
        l.add("B");
        l.add("C");

        Iterator<String> itr = l.iterator();
        while (itr.hasNext()) {
            String s = itr.next();
            if (s.equals("B")) {
                itr.remove(); // 정상적으로 제거됨
            }
        }
        System.out.println(l);
    }
}

실행 결과

[A, C]

위 코드에서 볼 수 있듯이, ArrayList의 반복자는 순회 중 remove() 메서드 호출을 지원하며 예외 없이 정상적으로 실행됩니다.

예제 2: CopyOnWriteArrayList 사용 예시

반면 CopyOnWriteArrayList의 반복자는 읽기 전용 스냅샷을 기반으로 동작하기 때문에, 순회 중 remove()를 호출하면 예외가 발생합니다.

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.*;

class CopyOnWriteArrayListDemo extends Thread {
    static CopyOnWriteArrayList<String> l = new CopyOnWriteArrayList<>();

    public static void main(String[] args) throws InterruptedException {
        l.add("A");
        l.add("B");
        l.add("C");

        Iterator<String> itr = l.iterator();
        while (itr.hasNext()) {
            String s = itr.next();
            System.out.println(s);
            if (s.equals("B")) {
                // RuntimeException 발생
                itr.remove();
            }
            Thread.sleep(1000);
        }
        System.out.println(l);
    }
}

실행 결과

A
B
Exception in thread "main" java.lang.UnsupportedOperationException

정리: 어떤 클래스를 선택해야 할까?

  • 단일 스레드 환경 또는 외부에서 동기화를 직접 관리할 수 있는 경우라면, 빠른 성능을 제공하는 ArrayList가 적합합니다.
  • 멀티 스레드 환경에서 읽기 작업이 쓰기 작업보다 훨씬 많은 경우에는 스레드 안전성을 보장하는 CopyOnWriteArrayList가 유리합니다. 단, 쓰기 작업 시마다 내부 배열 전체가 복사되므로 잦은 수정이 일어나는 상황에서는 비효율적일 수 있습니다.

두 클래스의 특성을 정확히 이해하고 애플리케이션의 동시성 요구 사항에 맞게 선택하는 것이 중요합니다.