김영한의 실전 자바 - 고급 1편(동시성 컬렉션)

2025. 1. 11. 23:06·김영한의 실전 자바 - 고급 1편

java.util 패키지의 ArrayList와 같은 컬렉션은 스레드 세이프할까?

  • 당연히 그렇지 않다.
  • 내부 동작이 모두 원자적 연산으로 구현이 되어 있지 않기 때문

 

ArrayList와 같은 컬렉션을 스레드 세이프하게 사용하려면 어떻게 해야 하는가?

  • ArrayList와 동일한 동작을 수행하는 컬렉션을 직접 구현한다.
  • 그 이후, ArrayList 내부 add, size, get 등의 함수에 synchronized 키워드를 추가

 

이러한 컬렉션이 여러개라고 할 때 효율적으로 개발하는 방법은?

  • 프록시 패턴을 도입하는 방법이 있음.
  • 예를 들어, SimpleList라는 인터페이스가 있고, 이 인터페이스를 구현한 basicList, SyncProxyList를 생성한다.
  • BasicList는 ArrayList와 동일한 기능을 하고 있고, 동시성 문제 해결이 필요함.
  • SyncProxyList는 SimpleList를 구현하되, 모든 함수가 Synchronized로 되어 있음.
  • 이 때, SyncProxyList가 BasicList를 감싸는 형태라면 BasicList도 동시성 문제가 해결될 수 있음.
  • BasicList와 같은 클래스가 여러개 일 경우 이 여러개는 모두 SyncProxyList로 감싸져 동시성 문제를 해결할 수 있음.

 

자바에서 제공하는 synchronized 프록시에 대해 설명하시오

 List<String> list = Collections.synchronizedList(new ArrayList<>());
  • 위와 같이 Collections를 사용해서 ArrayList와 같은 컬렉션을 Synchronize 프록시를 적용할 수 있음.
  • 이러면 클라이언트 -> SynchronizedRandomAccessList(프록시) -> ArrayList와 같이 동작함.
  • 하지만 이 방식 역시 여러 단점이 존재함.
    • 첫째, 동기화 오버헤드가 발생한다. 비록 synchronized 키워드가 멀티스레드 환경에서 안전한 접근을 보장하 지만, 각 메서드 호출 시마다 동기화 비용이 추가된다. 이로 인해 성능 저하가 발생할 수 있다.
      둘째, 전체 컬렉션에 대해 동기화가 이루어지기 때문에, 잠금 범위가 넓어질 수 있다. 이는 잠금 경합(lock contention)을 증가시키고, 병렬 처리의 효율성을 저하시키는 요인이 된다. 모든 메서드에 대해 동기화를 적용하 다 보면, 특정 스레드가 컬렉션을 사용하고 있을 때 다른 스레드들이 대기해야 하는 상황이 빈번해질 수 있다.
    • 셋째, 정교한 동기화가 불가능하다. synchronized 프록시를 사용하면 컬렉션 전체에 대한 동기화가 이루어지 지만, 특정 부분이나 메서드에 대해 선택적으로 동기화를 적용하는 것은 어렵다. 이는 과도한 동기화로 이어질 수 있다.
  • 즉, Lock을 걸어서 동시성 문제를 해결하는 것은 성능 저하를 불러일으킬 수 있고, 이에 따라 정교하게 필요한 부분만 딱 Lock을 걸어서 작업을 해야함.
  • synchornized 프록시와 같은 방법을 사용하면 정교한 컨트롤이 되지 않고 Lock의 범위가 넓어져 성능 저하를 야기할 수 있음.

 

동시성 컬렉션에 대해 설명하시오

  • java.util.concurrent 패키지는 고성능 멀티스레드 환경을 지원하는 다양한 동시성 컬렉션 클래스를 제공함
  • 이 컬렉션들은 더 정교한 잠금 메커니즘을 사용해 동시 접근을 효율적으로 처리하며, 필요한 경우 일부 메서드에만 동기화를 적용하는 유연한 동기화 전략을 제공함.
  • synchronized, lock(reentarantlock), CAS, 분할 잠금 등 다양한 기법이 도입 됨.
  • 자세한 구현은 복잡해 이해하기보다는 잘 활용하는 방법이 중요

자바 동시성 컬렉션 정리 표

종류 구현체 설명 기존 컬렉션 특징/ 사용사례
List CopyOnWriteArrayList 데이터 변경 시 내부 배열을 복사하여 새로 생성. 읽기 작업이 많고 쓰기 작업이 적을 때 효율적 ArrayList 스레드 안전한 리스트
Set CopyOnWriteArraySet 내부적으로 CopyOnWriteArrayList를 사용하여 구현된 동시성 Set HashSet 쓰기 작업이 적고 읽기 작업이 많을 때 사용
ConcurrentSkipListSet 정렬된 순서를 유지하며, 동시성 환경에서도 안전. Comparator 사용 가능 TreeSet 정렬이 필요한 Set
Map ConcurrentHashMap 비 차단(non-blocking) 해시맵으로, 락을 세분화하여 높은 성능을 보장 HashMap 스레드 안전한 맵
ConcurrentSkipListMap 정렬된 순서를 유지하며, 동시성 환경에서도 안전. Comparator 사용 가능 TreeMap 정렬이 필요한 Map
Queue ConcurrentLinkedQueue 비 차단(non-blocking) 동시성 큐로, FIFO(선입선출) 방식으로 동작 - 무한 크기 큐
Deque ConcurrentLinkedDeque 비 차단(non-blocking) 동시성 데크로, 양쪽에서 삽입/삭제 가능 - 무한 크기 데크
BlockingQueue ArrayBlockingQueue 크기가 고정된 블로킹 큐. 공정(fair) 모드를 지원함 - 제한된 리소스를 관리할 때 사용
LinkedBlockingQueue 크기가 무한하거나 고정된 블로킹 큐 - 일반적인 생산자-소비자 패턴
PriorityBlockingQueue 우선순위가 높은 요소를 먼저 처리하는 블로킹 큐 - 우선순위 작업 처리 시 사용
SynchronousQueue 데이터를 저장하지 않고 직접 전달하는 블로킹 큐 - 생산자-소비자 직접 거래
DelayQueue 요소가 지연 시간이 지난 후에야 소비될 수 있는 블로킹 큐 - 작업 스케줄링, 지연 작업 처리

'김영한의 실전 자바 - 고급 1편' 카테고리의 다른 글

김영한의 실전 자바 - 고급 1편(총 정리)  (0) 2026.01.26
김영한의 실전 자바 - 고급 1편(Executor)  (0) 2025.01.13
김영한의 실전 자바 - 고급 1편(CAS)  (1) 2025.01.11
김영한의 실전 자바 - 고급 1편(생산자 소비자 문제: Object - wait/notify, ReentarantLock - await/signal, BlockingQueue)  (1) 2025.01.08
김영한의 실전 자바 - 고급 1편(volatile, synchronized, LockSupport, ReentrantLock)  (1) 2025.01.05
'김영한의 실전 자바 - 고급 1편' 카테고리의 다른 글
  • 김영한의 실전 자바 - 고급 1편(총 정리)
  • 김영한의 실전 자바 - 고급 1편(Executor)
  • 김영한의 실전 자바 - 고급 1편(CAS)
  • 김영한의 실전 자바 - 고급 1편(생산자 소비자 문제: Object - wait/notify, ReentarantLock - await/signal, BlockingQueue)
5jyan5
5jyan5
  • 5jyan5
    jyan
    5jyan5
  • 전체
    오늘
    어제
    • 분류 전체보기 (242)
      • 김영한의 스프링 핵심 원리(기본편) (8)
      • 김영한의 스프링 핵심 원리 - 고급편 (11)
      • 김영한의 스프링 MVC 1편 (1)
      • 김영한의 스프링 DB 1편 (3)
      • 김영한의 스프링 MVC 2편 (3)
      • 김영한의 ORM 표준 JPA 프로그래밍(기본편) (9)
      • 김영한의 스프링 부트와 JPA 활용2 (2)
      • 김영한의 실전 자바 - 중급 1편 (1)
      • 김영한의 실전 자바 - 고급 1편 (9)
      • 김영한의 실전 자바 - 고급 2편 (9)
      • Readable Code: 읽기 좋은 코드를 작성.. (2)
      • 김영한의 실전 자바 - 고급 3편 (9)
      • CKA (118)
      • 개발 (37)
      • 경제 (4)
      • 리뷰 (1)
      • 정보 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      reentarantlock
      hibernate5module
      @args
      requset scope
      페치 조인
      typequery
      @within
      Thread
      log trace
      프록시
      gesingleresult
      @discriminatorvalue
      조회 성능 최적화
      단방향 맵핑
      김영한
      고급
      스레드
      jpq
      락
      양방향 맵핑
      자바
      @discriminatorcolumn
      cglib
      JPQL
      버퍼
      빈 후처리기
      jdk 동적 프록시
      프록시 팩토리
      Target
      WAS
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.2
    5jyan5
    김영한의 실전 자바 - 고급 1편(동시성 컬렉션)
    상단으로

    티스토리툴바