[Java] 컬렉션 프레임워크 동기화

Bam·2024년 3월 15일
0

Java

목록 보기
68/98
post-thumbnail

컬렉션 프레임워크를 다루면서 컬렉션 프레임워크의 컬렉션(ArrayList 등)과 구버전 컬렉션(Vector 등)을 이야기했었는데요. 두 컬렉션 간의 결정적 차이는 동기화 지원이었습니다.

구버전 컬렉션의 경우 자동으로 동기화를 지원해서, 싱글 쓰레드 프로그래밍인 경우에도 동기화를 수행하고 컬렉션 연산을 진행하기 때문에 비효율적인 성능을 보여주었습니다. 반면, 컬렉션 프레임워크의 컬렉션들은 동기화 기능은 Collections라는 클래스로부터 분리해서 사용하도록 만들어져 있어서 프로그래머가 원하는 상황에 맞춰서 동기화를 구현하거나 구현하지 않을 수 있게 되었다고 했었습니다.

그래서 오늘은 ArrayList 등의 컬렉션에서 멀티 쓰레드 환경을 위한 동기화 작업을 수행하는 방법을 소개드리려고 합니다.


Collections.synchronizedXxxxx();

컬렉션의 동기화 지원을 위해 Collections 클래스에서는 synchronizedXxxxx() 메소드를 지원하고 있습니다. Xxxxx에 사용하는 컬렉션의 타입을 지정하면 해당 컬렉션에 동기환된 컬렉션으로 반환해줍니다.

사용법은 컬렉션을 선언할 때 이 메소드를 사용하고, 인수로 컬렉션 생성자를 전달하면 됩니다.

List<T> list = Collections.synchronizedList(new ArrayList<T>());
Set<T> set = Collections.synchronizedSet(new HashSet<T>());
Map<K, V> map = Collections.synchronizedMap(new HashMap<K, V>());

주의할 점은 각 동기화 메소드의 반환 타입이 List, Set, Map이라는 점입니다.

메소드반환 타입
synchronizedList(List<T> list)List<T>
synchronizedSet(Set<T> set)Set<T>
synchronizedMap(Map<K, V> map)Map<K, V>

쓰레드로 동기화 확인하기

쓰레드를 이용해서 동기화 작업을 확인해보겠습니다.

우선 동기화가 없는 List입니다.

public class Main {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();	//동기화가 없는 List

        Thread t1 = new Thread() { //작업1: 리스트에 숫자 1000개 넣기
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    list.add(i);
                }
            }
        };

        Thread t2 = new Thread() {	//작업2: 리스트에 숫자 1000개 넣기
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    list.add(i);
                }
            }
        };

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (Exception e) {
            System.err.println(e);
        }

        System.out.println(list.size());
    }
}

작업1과 작업2가 모두 리스트에 숫자를 1000개씩 집어넣는 작업을 하니까 예상대로라면 list의 크기는 2000이 되어야 할 것입니다. 결과는 어떨까요? 동기화가 없기 때문에 두 쓰레드가 하나의 객체에 접근하는 과정에서 충돌하고 누락이 생겨서 2000개가 모두 저장되지 않았습니다.

자 그러면 동기화 메소드를 통해 동기화된 List를 이용해보겠습니다.

public class Main {
    public static void main(String[] args) {
        List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
        //동기화된 List

        Thread t1 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    list.add(i);
                }
            }
        };

        Thread t2 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    list.add(i);
                }
            }
        };

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (Exception e) {
            System.err.println(e);
        }

        System.out.println(list.size());
    }
}

요소 2000개가 무사히 삽입이 되었죠?

0개의 댓글