[Java] Volatile

2024. 11. 19. 20:33·Java
 

 

들어가기 전

Volatile은 성능을 포기하고 변경된 값을 정확히 본다 생각하면 된다.

CPU에서는 일반적으로 효율적인 처리를 하기 위해 캐시 메모리에 값을 불러오고, CPU는 캐시메모리에 있는 값을 사용한다.

다음 문제를 한 번 보자

public class VolatileFlagMain {
    public static void main(String[] args) {
        MyTask task = new  MyTask();
        Thread t = new Thread(task, "work");
        log("runFlag = " + task.runFlag);
        t.start();

        sleep(1000);
        log("runFlag를 false로 변경 시도");
        task.runFlag = false;
        log("runFlag = " + task.runFlag);
        log("main 종료");
    }

    static class MyTask implements Runnable {
        boolean runFlag = true;

        @Override
        public void run(){
            log("task 시작");
            while(runFlag){
                //  runFlag가 false로 변하면 탈출
            }
            log("task 종료");
        }
    }
}

다음 문제는 스레드 생성 이후 runFlag를 true에서 false로 바꿔 작업을 끝내게 하고 싶은 코드이다.

일반적으로  이 문제에 대한 코드를 보면 

고마워요 영한T..

다음과 같이 Flow를 생각할지도 모르지만 실제로 코드를 실행하면 다음과 같은 결과를 받는다.

코드에선 분명 runFlag의 값을 false로 변경된 걸 확인하고,  While문을 탈출해 task가 종료되어야 하는데

다음 결과에서 보이듯 task 종료가 이뤄지지 않고 계속 실행이 돌아가는 문제가 생긴다. 왜 그런걸까? 


캐시 메모리의 존재

"task 종료"가 이뤄지지 않는 이유는 바로 캐시 메모리 때문이다.

runFlag를 true로 설정하게 되면 효율적인 처리를 위해 멀리있는 인스턴스를 직접 받는것이 아닌 캐시 메모리에서 1차적으로 불러오고

이를 CPU에서 처리하게 되는데 코드를 확인해보면 main에서 runFlag의 값을 바꿔준다. 이렇게 수행하게 되면

다음과 같이 메인메모리가 바뀌는 것이 아니라 캐시 메모리에서 반영이 되어 상태를 조회할 때 false로 나옴에도 불구하고, 메인 메모리와 work스레드에는 즉시 반영이 되지 않아서 종료되지 않는 문제가 발생하는 것이다.

 


 

volatile !

그럼 어떻게 해야 메인 메모리와 work 스레드가 즉시 반영이 될 수 있을까?

바로 volatile을 사용하는 것이다. 들어가기전 volatile은 성능을 포기하고 변경된 값을 정확히 본다고 표현했는데. 그 이유는 바로

캐시 메모리를 제어하기 때문이다. 효율적인 처리를 위해선 캐시 메모리를 사용해야하지만,  이 volatile의 경우 캐시 메모리에 접근하는 것이 아닌 메인 메모리에 직접 접근하기 때문에 runFlag를 false로 바꾸게 된다면 다음과 같이 흐름도를 형성한다.

그러나 캐시 메모리를 사용하지 않는 점에 있어서 성능이 느려지기 때문에 주의해서 사용할 필요가 있다.


 

적용해보기

그럼 앞선 코드를 개선하면 어떻게 구성하고, 어떤 결과를 얻을 수 있을까?

public class VolatileFlagMain {
    public static void main(String[] args) {
        MyTask task = new  MyTask();
        Thread t = new Thread(task, "work");
        log("runFlag = " + task.runFlag);
        t.start();

        sleep(1000);
        log("runFlag를 false로 변경 시도");
        task.runFlag = false;
        log("runFlag = " + task.runFlag);
        log("main 종료");
    }

    static class MyTask implements Runnable {
        volatile boolean runFlag = true;

        @Override
        public void run(){
            log("task 시작");
            while(runFlag){
                //  runFlag가 false로 변하면 탈출
            }
            log("task 종료");
        }
    }
}

이전코드와 비교했을 때 boolean runFlag앞에 volatile을 붙여준 것 밖에 없다. 그럼 결과는 어떻게 될까?

 

다음과 같이 runFlag를 false로 변경하자마자 while문에서 확인 후 task가 종료되고, 이 후 main도 종료되는 부분을 확인 할 수 있다.


 

마무리

오늘 프로젝트 발표까지 끝내며 팀원들 코드부터, 다른 사람들의 ERD, 구현방식과 튜터님의 피드백을 들으면서 단순히 자바만 무작정 공부하는 것이 아니라, 스프링에 대해서도, 문제 접근에 대해서 어떻게 해야할지도 많이 배웠던 시간이었으나, 한 편으로는 구현을 마무리짓지 못한 부분에 대해서 팀원한테 미안함이 너무 컸다.

 

'Java' 카테고리의 다른 글

[Java] reverse()  (1) 2024.11.13
[Java] Thread Join  (2) 2024.11.12
[Java] Record  (4) 2024.11.11
[Java] What is NullPointException?  (0) 2024.09.24
[Java] Linear Search AND Binary Search  (2) 2024.09.03
'Java' 카테고리의 다른 글
  • [Java] reverse()
  • [Java] Thread Join
  • [Java] Record
  • [Java] What is NullPointException?
dev-heesxxung
dev-heesxxung
  • dev-heesxxung
    발악하는 비전공자 여우
    dev-heesxxung
  • 전체
    오늘
    어제
    • 분류 전체보기 (16)
      • Java (7)
      • Spring (1)
      • 밑시딥 (1)
      • Thesis (5)
      • AI (1)
      • Sparta[심화 2기] (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    NullPointException
    conjunctivitis
    Spring
    특징점 추출(feature detection)
    java
    영상처리(image processing)
    실시간 객체인식(real-time object recognition)
    ai
    Computer Vision
    Thread
    컴퓨터비전
    템플릿 매칭(template matching)
    관심 영역 기반
    CS
    어텐션기법
    Coding
    master student
    인식속도(recognition speed)
    의료 영상 분석
    programming
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
dev-heesxxung
[Java] Volatile
상단으로

티스토리툴바