You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
실행 결과의 차이점은 “task 종료”이다. → work스레드에 while문에서 빠져나오지 못하고 있는 것
왜 그런걸까 ? 아래에서 계속
2️⃣ volatile, 메모리 가시성2
메모리 가시성이라는 것에 대해서 알아보자.
위에서 문제점을 찾아보자.
일반적으로 생각하는 메모리 접근 방식
main 스레드와 work 스레드는 각각의 CPU 코어에 할당되어서 실행된다.
물론 CPU코어가 1개라면 빠르게 번갈아 가면서 실행될 수 있다.
점선 위쪽은 스레드의 실행 흐름을 나타내고, 점선 아래쪽은 하드웨어를 나타낸다.
프로그램을 실행하고 main 스레드와 work 스레드는 모두 메인 메모리의 runFlag의 값을 읽는다.
프로그램의 시작 시점에는 runFlag 를 변경하지 않기 때문에 모든 스레드에서 true 의 값을 읽는다.
참고로 runFlag 의 초기값은 true 이다.
work 스레드의 경우 while(runFlag[true]) 가 만족하기 때문에 while문을 계속 반복해서 수행한다
main 스레드는 runFlag 값을 false로 변경
메인 메모리의 runFlag 값이 false로 설정한다.
work 스레드는 while(runFlag)를 실행할 때, runFlag의 데이터를 메모리에서 확인한다.
runFlag의 값이 false이므로 while문을 탈출, “task 종료”를 출력한다.
실제 메모리의 접근 방식
CPU는 처리 성능을 개선하기 위해 중간에 캐시 메모리라는 것을 사용한다.
메인 메모리는 CPU 입장에서 보면 거리도 멀고, 속도도 상대적으로 느리다. 대신에 상대적으로 가격이 저렴해서큰 용량을 쉽게 구성할 수 있다.
CPU 연산은 매우 빠르기 때문에 CPU 연산의 빠른 성능을 따라가려면, CPU 가까이에 매우 빠른 메모리가 필요 한데, 이것이 바로 캐시 메모리이다. 캐시 메모리는 CPU와 가까이 붙어있고, 속도도 매우 빠른 메모리이다. 하지만 상대적으로 가격이 비싸기 때문에 큰 용량을 구성하기는 어렵다.
현대의 CPU 대부분은 코어 단위로 캐시 메모리를 각각 보유하고 있다.
참고로 여러 코어가 공유하는 캐시 메모리도 있다.
각 스레드가 runFlag의 값을 사용하면 CPU는 이 값을 효율적으로 처리하기 위해 runFlag를 캐시 메모리에 불러온다.
그리고 이후에는 캐시 메모리에 있는 runFlag를 사용하게 된다.
자바 프로그램을 실행하고 main 스레드와 work 스레드는 모두 runFlag 의 값을 읽는다.
CPU는 이 값을 효율적으로 처리하기 위해 먼저 캐시 메모리에 불러온다.
main 스레드와 work 스레드가 사용하는 runFlag 가 각각의 캐시 메모리에 보관된다.
프로그램의 시작 시점에는 runFlag 를 변경하지 않기 때문에 모든 스레드에서 true 의 값을 읽는다.
참고로 runFlag 의 초기값은 true 이다.
work 스레드의 경우 while(runFlag[true]) 가 만족하기 때문에 while문을 계속 반복해서 수행한다.
캐시 메모리에 있는 runFlag 의 값이 언제 메인 메모리에 반영될까? → 알 수 없다.
✅ 메모리 가시성(memory visibility)
멀티스레드 환경에서 한 스레드가 변경한 값이 다른 스레드에서 언제 보이는지에 대한 문제를 메모리 가시성이라 한다. 이름 그대로 메모리에 변경한 값이 보이는가, 보이지 않는가의 문제이다.
멀티스레드 환경에서 한 스레드가 변경한 값이 다른 스레드에서 언제 보이는지에 대한 것을 메모리 가시성(memory visibility)이라 한다. 이름 그대로 메모리에 변경한 값이 보이는가, 보이지 않는가의 문제이다.
✅Java Memory Model에서 핵심은
핵심은 여러 스레드들의 작업 순서를 보장하는 happens-before 관계에 대한 정의다.
✅happens-before
happens-before 관계는 자바 메모리 모델에서 스레드 간의 작업 순서를 정의하는 개념이다. 만약 A 작업이 B 작업보다 happens-before 관계에 있다면, A 작업에서의 모든 메모리 변경 사항은 B 작업에서 볼 수 있다. 즉, A 작업에서변경된 내용은 B 작업이 시작되기 전에 모두 메모리에 반영된다.
happens-before 관계는 이름 그대로, 한 동작이 다른 동작보다 먼저 발생함을 보장한다.
happens-before 관계는 스레드 간의 메모리 가시성을 보장하는 규칙이다.
happens-before 관계가 성립하면, 한 스레드의 작업을 다른 스레드에서 볼 수 있게 된다.
즉, 한 스레드에서 수행한 작업을 다른 스레드가 참조할 때 최신 상태가 보장되는 것이다.
이 규칙을 따르면 프로그래머가 멀티스레드 프로그램을 작성할 때 예상치 못한 동작을 피할 수 있다.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
섹션 5. 메모리 가시성
1️⃣ volatile, 메모리 가시성1
main스레드, work 스레드 모두 MyTask 인스턴스(x001)에 있는 funFlag를 사용한다.
이 값을 false로 변경하면 work 스레드의 작업을 종료할 수 있다.
우리가 기대 하는 실행 결과
하지만…
실행 결과의 차이점은 “task 종료”이다. → work스레드에 while문에서 빠져나오지 못하고 있는 것
왜 그런걸까 ? 아래에서 계속
2️⃣ volatile, 메모리 가시성2
메모리 가시성이라는 것에 대해서 알아보자.
위에서 문제점을 찾아보자.
일반적으로 생각하는 메모리 접근 방식
참고로 runFlag 의 초기값은 true 이다.
✅ 메모리 가시성(memory visibility)
멀티스레드 환경에서 한 스레드가 변경한 값이 다른 스레드에서 언제 보이는지에 대한 문제를 메모리 가시성이라 한다. 이름 그대로 메모리에 변경한 값이 보이는가, 보이지 않는가의 문제이다.
3️⃣ volatile, 메모리 가시성3
4️⃣ volatile, 메모리 가시성4
✅work 스레드
✅main 스레드
CPU 환경에 따라 다름
보류..
5️⃣ 자바 메모리 모델(Java Memory Model)
✅메모리 가시성
✅Java Memory Model에서 핵심은
✅happens-before
이 규칙을 따르면 프로그래머가 멀티스레드 프로그램을 작성할 때 예상치 못한 동작을 피할 수 있다.
✅happens-before 관계가 발생하는 경우
프로그램 순서 규칙
volatile 변수 규칙
스레드 시작 규칙
스레드 종료 규칙
인터럽트 규칙
객체 생성 규칙
모니터 락 규칙
All reactions