ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ConcurrentHashMap
    알고리즘과 언어/java 2022. 1. 15. 01:33

     

    * 다른 블로거들의 글들을 요약정리한 글입니다. 아래 url을 남겨놓았습니다. *

     

    ConcurrentHashMap

     

    ConcurrentHashMap을 알기 전에 Thread-Safe에 대해 알아보았다.

    또한 JAVA에서 Thread-Safe를 고려해야 하는 상황에 대해 간단히 정리했다.

     


    Thread-Safe

    동기화(Synchronize)라고 표현하기도 하며 어떠한 Class의 인스턴스가 여러 개의 Thread에서 동시 참조되고 해당 객체에 Operation이 발생해도 정합성을 유지해줄 때 Thread-Safe 하다라고 표현

    • cf. 정합성 - 데이터가 서로 모순이 없이 일관되게 일치
    • @ThreadSafe 어노테이션을 이용해 해당 Class가 Thread-Safe 함을 표시하기도 함.

    Java에서 Thread-Safe 고려해야 하는 경우

    1. 스트링 빈(bean)
    2. Cache
    3. ConcurrentHashMap
    4. StringBuffer
    5. int를 thread-safe하게 사용

     

    1. 스트링 빈(bean) : 인스턴트 멤버 변수가 있는 경우 스레드 세이프하지 않다.

    set 메소드를 이용하면 변수가 바뀌는데, 다른 스레드 입장에서는 예상치 못한 변화로 문제를 일으킬 수 있음

    -> 인스턴트 멤버 변수가 아닌 지역 변수를 사용하는 것을 권장

     

     

    2. 동기화에 Cache도 고려하기. 직접 참조하지 않고, L1, L2 캐시를 참조하는 경우가 있기 때문에.

    -> volatile로 해결.

     

    Java volatile :

    • Java 변수를 Main Memory에 저장하겠다는 것.
    • (Read, Write를 CPU cache가 아닌, Main Memory에서 하는 것.)
    • Cache를 사용하게 되면 Thread1이 계속 공유되는 변수 값을 증가시키더라도 Thread2의 캐시는 업데이트되지 않아서 값이 일치하지 않음.
    • Read - Write의 값 일치는 보장하지만 여러 쓰레드가 Write 하는 경우는 보장할 수 없기에 synchronized 해야 함.
    • 캐시를 사용하지 않기에 성능에 문제를 줄 수 있음.

    또한, 인스턴스 변수를 변경하지 않는 메서드(단순히 읽거나 리턴하는)라고 하더라도 동기화 처리(synchronized) 해주지 않으면 동기화가 깨진다.

     

     

    3. ConcurrentHashMap

    • HashMap : 성능은 좋지만 Thread-safe하지 않다.
    • Hashtable : 성능이 좋지 않지만 Thread-safe하다.

    Hashtable은 method 전체에 synchronized 키워드를 사용 (메서드 전체가 임계 구역)

    → 누군가 put으로 lock을 획득 중이면, 다른 스레드는 get도 진입할 수 없다.

    Thread-safe 하지만 멀티 쓰레드 환경에서는 느리다.

    • ConcurrentHashMap : Hashtable보다 성능이 좋고 Thread-safe 하다.

    get()에는 synchronized가 없고, put()의 중간에 synchronized가 있다. (메서드 전체가 임계 구역이지 않다.)

    → 읽기 작업에는 여러 Thread가 읽을 수 있지만, 쓰기 작업에는 특정 세그먼트 or 버킷에 대한 lock을 사용

    검색 작업(get)은 lock이 이뤄지지 않으며 갱신작업(put)과 동시에 할 수 있기에 병목현상이 적다.

     

    결론 : ConcurrentHashMap은 Thread-safe 하고 Hashtable보다 성능이 뛰어나다.

    검색(get)은 검색 method가 호출되는 시점에, 가장 최신에 완료된 업데이트 작업의 결과가 반영된다.

     

     

    4. StringBuffer

    • String vs StringBuffer, StringBuilder

    String은 immutable(불변)하고 StringBuffer와 StringBuilder는 mutable(가변)

    • StringBuffer vs StringBuilder

    StringBuffer는 멀티스레드 환경에서 synchronized 키워드가 가능하므로 동기화가 가능하다. (thread-safe) 

    StringBuilder는 thread-safe하지 않다. 그러나 동기화를 고려하지 않기에 싱글 스레드에서 연산 (+ 등)이 빠르다.

     

     

    5. int를 thread-safe 하게 사용

    JAVA에서 동시성 문제를 해결하는 3가지 방법 :

    (1. volatile - read/write만, 2. synchronized - 동시성 보장하나 비용이 큼, 3. Atomic Type)

     

    int의 경우 Atomic은 AtomicInteger.

    → Atomic은 CAS(Compare And Swap) 방식에 기반하여 동기화 문제를 해결

    CAS란 변수의 값을 변경하기 전에 기존에 가지고 있던 값이 내가 예상하던 값과 같을 경우에만 새로운 값으로 할당하는 방법

    한 번에 단 하나의 스레드만 변수의 값을 변경할 수 있도록 한다.

     

     

    참고 사이트

    https://nesoy.github.io/articles/2018-06/Java-volatile

    https://jeong-pro.tistory.com/227

    https://siyoon210.tistory.com/140

    https://doorisopen.github.io/developers-library/Java/2020-07-08-java-hashmap-and-thread-safe

    https://jeong-pro.tistory.com/85

    '알고리즘과 언어 > java' 카테고리의 다른 글

    jpa양방향 매핑 시 무한루프 ...  (0) 2023.06.04
    Java는 모두 call by value다?  (0) 2022.03.23
Designed by Tistory.