• 티스토리 홈
starryeye
  • 프로필사진
    starryeye
    • 분류 전체보기 (189)
      • C++ (17)
      • Java (24)
      • OOP (5)
      • Spring Reactive Stack (12)
        • Reactive Streams (3)
        • Netty (4)
        • Reactor (1)
        • Webflux (3)
        • DB, Cache 연동 (1)
      • Spring (90)
        • Core (17)
        • MVC (33)
        • Client (2)
        • Security (4)
        • DB, Cache 연동 (33)
      • DataBase (12)
        • RDBMS (2)
        • NoSQL (10)
      • Message Broker (6)
      • Web (4)
      • Network (4)
      • 대규모 시스템 설계 (15)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • [Java 정리] Thread 6
        2022년 08월 22일
        • starryeye
        • 작성자
        • 2022.08.22.:07

        이미 알던 지식이지만, 기본으로 돌아가서.. Java의 관점에서 한번 정리해보자.

         

        volatile

        멀티 코어 프로세서 환경에서는 

        코어마다 별도의 캐시(레지스트리)를 가지고 있다.

         

        코어는 메모리에서 읽어온 값을 캐시에 저장하고 캐시에서 값을 읽어서 작업한다.

        다시 같은 값을 읽을 때는 캐시에 존재하지 않을 경우에만 메모리에서 읽어 온다.

         

        그러면..

        A코어에 의해 메모리에 저장된 변수의 값이 변경 되었는데.. B코어의 캐시에 저장된 값이 갱신 되지 않았다면..

        데이터가 다르므로.. 프로그램은 예상치 못한 흐름으로 동작한다.

         

        해결법은..

        변수 앞에 volatile 키워드를 붙이면 코어가 변수의 값을 읽을 때 항상 메모리에서 읽어오게 된다.

        따라서.. 캐시와 메모리간의 값의 불일치가 해결된다.

         

         

        volatile은 해당 변수에 대해 Read Write가 원자화 된다.

        JVM은 데이터를 4byte 단위로 처리한다.

        따라서 int와 int보다 작은 타입은 한번에 읽거나 쓰는 것이 가능하다.

        (단 하나의 명령어)

         

        하지만..

        크기가 8byte인 long, double은 하나의 명령어로 Read/Write가 불가능 하기 때문에..

        변수의 Read/Write 과정에서 다른 쓰레드가 끼어들 여지가 생긴다.

        그럴때 volatile 키워드를 사용한다.

         

        <참고>

        volatile은 "변수"에 대해 읽기와 쓰기가 원자화 되는 것이다.

        "여러 코드 문장"을 원자화한 synchronized 블럭을 이용하여

        쓰레드의 동기화를 구현한 것과 구분해야한다.

         

        volatile long balance;
        
        int getBalance() {
            return balance;
        }
        
        synchronized void withdraw(int money) {
            if(balance >= money)
                balance -= money;
        }

        위 코드에서 개발자의 의도는 돈이 인출 되는 도중에는 잔고를 확인 할 수 없게.. 하자였다고 치자.

        위 코드에서는 getBalance() 메서드에서 synchronized 키워드를 사용하지 않았다..

        이는 잘못된 개발 코드이다.

         

        balance 변수에 volatile 키워드가 붙어있어서 단순히 원자화 되었으니

        (메서드 단위의)동기화가 되겠거니.. 라는 생각은 큰 오산이다.

         

        쓰레드 A가 락을 획득하고 withdraw() 메서드가 동작되는 상황에서

        getBalance()가 쓰레드 B에 의해 호출되면.. volatile 변수기 때문에 "변수"의 쓰기와 읽기만 원자화된다.

        실제로..

        돈이 인출되기 전에 getBalance가 수행될 수도..

        돈이 인출된 후에 getBalance가 수행될 수도.. 있다..

         

        따라서, getBalance()메서드에 synchronized 키워드를 붙여줘야 한다.

        'Java' 카테고리의 다른 글

        불변 객체, lombok @Value 와 Java Record  (0) 2023.05.07
        [Java 정리] ThreadLocal  (0) 2022.10.19
        [Java 정리] Thread 5  (0) 2022.08.22
        [Java 정리] Thread 4  (0) 2022.08.22
        [Java 정리] Thread 3  (0) 2022.08.19
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바