Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

To Dare Is To Do!

자바의 동시성 이슈 (가시성 문제, volatile) 본문

Java

자바의 동시성 이슈 (가시성 문제, volatile)

Nick_Choi 2024. 7. 16. 21:37

여러 스레드를 활용하면 시스템의 자원 사용, 응답 시간, 문맥 교환 횟수를 줄이는 등의 장점을 얻을 수 있지만 데이터의 충돌 문제 즉 동시성을 보장할 수 없는 문제를 초래할 수 있다.

 

CPU가 작업을 수행하기 위한 데이터를 읽을 때 RAM의 일부분을 CPU Cache Memory로 읽어들이고

CPU가 작업에 대한 결과를 RAM에 저장할 때는 다시 CPU Cache Memory보내고 이들은 적절한 시점에 RAM으로 쓰기 작업을 수행한다.

이러한 읽고 쓰는 과정에서 CPU Cache Memory들은 CPU가 읽거나 쓰는 작업을 수행했지만 효율성 및 일관성의 이유로 RAM에 해당 작업들을 바로 수행하진 않는다.

 

동시성 프로그래밍에서는 CPU와 RAM의 중간에 위치하는 CPU Cache Memory와 병렬성이라는 특징으로 인하여 다수의 스레드가 공유 자원에 접근할 때 가시성과 원자성의 문제가 발생할 수 있다.

 

가시성의 문제

가시성이란?

멀티스레드 환경에서 각각의 스레드가 공유자원에 대해서 모두 같은 상태를 바라보고 있는 것을 의미한다.

 

가시성의 정의와 위의 CPU와 RAM의 관계를 고려하여 가시성의 문제를 풀어보면

결국 CPU Cache Memory가 CPU의 의도대로 즉시 작업을 수행하지 않아 CPU가 바라보는 데이터와 RAM의 데이터와 일치하지 않음으로써 발생하는 것이다.

 

이를 해결하기 위해서는 CPU가 필요로하는 데이터들 즉 가시성이 보장되어야 하는 데이터들은 CPU Cache Memory가 아닌 RAM에서 직접 가져와야 하며 이는 volatile 키워드를 활용해서 해결할 수 있다.

 

volatile

volatile 키워드를 사용하면 해당 데이터들의 가시성을 보장할 수 있다.

다음과 같은 상황을 통해 어떻게 사용되는지 살펴보자.

public class Volatile {

    private static boolean stopRequested;

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(() -> {
            int i = 0;
            while (!stopRequested) {
                i++;
            }
        });
        backgroundThread.start();

        Thread.sleep(5000);
        stopRequested = true;
    }
}

 

위의 코드에는 main 스레드와 backgroundThread가 실행되는 예제이다.

이 코드의 실행결과로 우리가 기대하는 것은 

backgroundThread 속 반복문이 main 스레드가 5초 후에 실행한 'stopRequested = true;' 코드 때문에 중지되는 것이다.

하지만 우리는 실행 결과로 background 속 반복문이 영원히 실행되는 상황을 맞이할 수 있다.

그림에서 CPU1의 thread를 backgroundThread, CPU2의 thread를 main 스레드라고 보자

main 스레드가 Cache Memory2를 통해 RAM에 공유 변수 stopRequested의 값을 true로 쓰는 작업을 수행했다.

하지만 backgroundThread는 Cache Memory1을 통해 수정되지 않은 stopRequested 값을 읽었다면 backgroundThread 속 반복문은 여전히 실행되고 있을 것이다.

이렇게 각각의 스레드들이 공유자원에 대해서 같은 상태를 바라보고 있지 않은 상황은 가시성이 보장되지 않은 상황이라 할 수 있다.

이 때 공유 변수에 volatile 키워드를 사용한다면 스레드에서 RAM으로 직접 접근하여 읽고 쓰는 작업을 수행할 수 있고

이는 가시성을 보장하여 문제를 해결한다.

public class Volatile {

    private static volatile boolean stopRequested;

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(() -> {
            int i = 0;
            while (!stopRequested) {
                i++;
            }
        });
        backgroundThread.start();

        Thread.sleep(5000);
        stopRequested = true;
    }
}

 

 

 

 

 


https://ecsimsw.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%9D%98-%EB%8F%99%EA%B8%B0%ED%99%94

-%EB%B0%A9%EC%8B%9D-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B0%80%EC%8B%9C%EC%84%B1%EC%9D%B4%EB%9E%80-synchronized-volatile-atomic

 

자바의 동기화 방식

자바의 Thread Safe여러 스레드를 사용하면 시스템 자원의 사용, 응답시간, Context Switch 횟수를 줄일 수 있다는 장점을 얻을 수 있다. 대신 데이터의 충돌 문제가 발생할 수 있다.  여러 테스크가

www.blog.ecsimsw.com

 

https://highright96.tistory.com/104

 

 

[Java] 자바의 동시성 이슈

Java 스터디를 진행하며 작성한 글입니다. 이번 글에서는 자바에서 동시성(공유자원 접근)으로 인해 발생할 수 있는 문제점과 이를 해결할 수 있는 방법에 대해 살펴보려 한다. 동시성 프로그래

highright96.tistory.com

 

'Java' 카테고리의 다른 글

Checked Exception과 Unchecked Exception  (0) 2024.07.22
자바의 동시성 이슈 (원자성 문제, atomic)  (0) 2024.07.19
synchronized  (0) 2024.07.10
thread  (0) 2024.07.05
오버로딩과 오버라이딩  (0) 2024.07.04