JAVA

[JAVA] Map 동기화 멀티스레딩

인생아 2024. 11. 5. 17:15
반응형

Java에서는 멀티스레딩 환경에서 안전하게 Map을 사용하기 위해 여러 가지 동기화 방법을 제공합니다. 대표적으로 Collections.synchronizedMap()ConcurrentHashMap이 있으며, 각 방법은 동시성 문제 해결동기화 방식을 다르게 처리합니다. 이 글에서는 Collections.synchronizedMap()과 ConcurrentHashMap의 차이, ConcurrentMap 인터페이스의 동시성 문제 해결 그리고 동기화가 필요한 경우와 그렇지 않은 경우를 설명하고 예제를 통해 이해를 돕겠습니다.

Collections.synchronizedMap()과 ConcurrentHashMap의 차이

Collections.synchronizedMap()은 기존의 HashMap동기화 처리를 추가해 여러 스레드가 접근할 때 안전하게 사용할 수 있게 만듭니다. 그러나 모든 메서드에 synchronized 키워드가 적용되어 있어, 성능 면에서는 제약이 있을 수 있습니다. 반면, ConcurrentHashMap내부적으로 여러 개의 세그먼트를 사용하여 동시성 제어를 하므로, synchronizedMap보다 높은 성능을 제공합니다.

Collections.synchronizedMap() 예제

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class SynchronizedMapExample {
    public static void main(String[] args) {
        Map<String, Integer> map = Collections.synchronizedMap(new HashMap<>());

        map.put("Key1", 10);
        map.put("Key2", 20);

        synchronized (map) { // 전체 Map을 동기화
            for (String key : map.keySet()) {
                System.out.println(key + ": " + map.get(key));
            }
        }
    }
}

 

위 예제는 Collections.synchronizedMap()을 사용해 HashMap을 동기화한 것입니다. synchronized 블록 안에서 Map을 안전하게 순회할 수 있지만, 모든 스레드가 Map에 접근할 때마다 전체 객체가 잠금(lock) 상태가 되므로 성능 저하가 발생할 수 있습니다.

ConcurrentHashMap 예제

import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        Map<String, Integer> map = new ConcurrentHashMap<>();

        map.put("Key1", 10);
        map.put("Key2", 20);

        // ConcurrentHashMap은 전체 잠금을 걸지 않음
        for (String key : map.keySet()) {
            System.out.println(key + ": " + map.get(key));
        }
    }
}

ConcurrentHashMap은 전체 Map을 잠그지 않고 부분적으로 잠금이 걸려, 여러 스레드가 동시에 데이터를 수정하거나 읽는 데 용이합니다. 따라서 대규모 멀티스레드 환경에서 성능이 뛰어납니다.

동시성 문제 해결과 ConcurrentMap 인터페이스

ConcurrentMap 인터페이스멀티스레드 환경에서 안전하게 Map을 사용할 수 있도록 다양한 동시성 메서드를 제공합니다. 이 인터페이스는 ConcurrentHashMap에서 구현되며, putIfAbsent(), remove(), replace() 등의 원자적(atomic) 연산 메서드를 통해 여러 스레드가 동시에 작업할 때 발생할 수 있는 문제를 방지합니다.

ConcurrentMap 메서드 예제

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class ConcurrentMapMethodsExample {
    public static void main(String[] args) {
        ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();

        // 키가 없을 때만 값을 삽입
        map.putIfAbsent("Key1", 10);

        // 특정 키와 값이 일치할 때만 제거
        map.remove("Key1", 10);

        // 기존 값이 일치할 때 새로운 값으로 대체
        map.replace("Key2", 20, 30);

        System.out.println(map);
    }
}

ConcurrentMap 메서드들은 원자적 연산을 지원하기 때문에, 여러 스레드가 동시에 putIfAbsent(), remove(), replace() 등의 메서드를 호출하더라도 데이터 무결성을 유지합니다. 이러한 메서드를 활용하면 멀티스레딩 환경에서 데이터의 일관성을 쉽게 확보할 수 있습니다.

동기화가 필요한 경우와 그렇지 않은 경우

멀티스레드 환경에서 동기화가 필요한 경우는 다음과 같습니다:

  • 여러 스레드가 동시에 데이터를 읽고 수정하는 경우
  • 데이터의 일관성정확성이 중요한 경우

그러나 아래와 같은 경우는 동기화가 필요하지 않습니다:

  • Map이 단일 스레드 환경에서만 사용될 때
  • 데이터의 일관성이 그렇게 중요하지 않은 경우

따라서, 성능을 위해 가능한 동기화를 최소화하는 것이 좋으며, 멀티스레딩 환경이 아니라면 굳이 synchronizedMap이나 ConcurrentHashMap을 사용할 필요가 없습니다.

참고사이트

반응형