JAVA

멀티스레드 메모리 접근 방식/메모리 가시성/happens-before

silver-w 2024. 11. 21. 22:47

실제 메모리의 접근 방식


 각 CPU마다 캐시 메모리라는 것을 사용한다, 메인 메모리는 CPU입장에서 거리도 멀고, 속도도 상대적 느리다. 

해당 캐시 메모리는 CPU의 빠른 연산을 위해 CPU와 가까이 붙어있고, 속도도 빠른 메모리이다. 보통 코어 단위로 캐시 메모리를 각각 보유하고있다.

volatile을 사용하지 않을 경우 메인 메모리(힙 영역)에 있는 변수의 값을 각 캐시 메모리에서 불러오고, 그 이후 캐시 메모리에 있는 변수의 값을 사용하게 된다.

 

멀티스레드 환경에서 volatile 없이 변수의 값을 변경하는 경우


 

main 스레드에서 runFlag 변수의 값을 true 에서 false로 바꾸는 경우,

메인메모리와 work스레드를 연산하는 CPU가 사용하는 캐시 메모리에 바로 반영이 되지 않는다.

그러므로, 공유하는 변수의 값이 서로 달라 원하지 않는 결과를 초래한다. 

 

이때 work 스레드의 runFlag의 값도 변경하기 위해서 2가지 과정이 필요하다.

(1) 메인메모리에 runFlag = false 를 반영
(2) CPU 코어2의 캐시 메모리가 메인메모리에서 runFlag=false 를 불러오기

하지만, 이는 CPU 설계 방식과 실행환경에 따라 언제 반영될지 "알수 없다". 

(주로 컨텍스트 스위칭(콘솔창에 출력할때 등...)될때 반영되는데, 이 또한 환경에 따라 다르다.)

 

메모리 가시성


메모리 가시성 : 멀티 스레드 환경에서 한 스레드가 변경한 값이 다른 스레드에서 언제 보이는지에 대한 것

 

공유하는 변수를 volatile로 선언하면 이를 확보 할 수 있다. 

 

volatile 유무에 따른 메모리 접근 방법과 장단점

volatile을 사용하지 않을 때
: 메인 메모리에 있는 값을 캐시 메모리에서 불러와서 사용,  캐시 메모리에 있는 값을 사용하므로 속도가 빠르다. 
단, 멀티 스레드 환경에서는  컨텍스트 스위칭 등 여러 환경에 따라 언제 메모리 가시성이 확보되는지 알 수 없음.
volatile을 사용할 때
: 각 스레드를 연산하는 CPU 가 캐시 메모리에 해당 변수의 값을 참조하는 것이 아닌, 메인 메모리에서 변수의 값을 직접 불러와서 연산. 단 캐시 메모리가 아닌 메인 메모리에 접근하므로 속도가 느리다. 
그러므로, 꼭 필요한 곳에만 volatile을 사용하는 것이 좋다.

 

volatile 또는 스레드 동기화 기법을 사용하면 메모리 가시성의 문제가 발생하지 않는다.

happens-before 관계


§ 메모리 가시성 : 멀티 스레드 환경에서 한 스레드가 변경한 값이 다른 스레드에서 언제 보이는지에 대한 것

§ JMM(Java Memory Model) : 자바 프로그램이 어떻게 메모리에 접근하고 수정할 수 있는지 규정, 멀티스레드 프로그래밍에서는 스레드 간 상호작용을 정의(happens-before)

 

§ happens-before : 자바 메모리 모델에서 스레드 간의 작업 순서를 정의

 - 한 스레드의 동작이 다른 스레드 보다 먼저 발생하고  스레드 간 메모리 가시성 보장

 

1. 프로그램 순서 규칙
   : 단일 스레드 내에서 프로그램 순서대로 작성된 명령문은 happens-before 순서대로 실행된다.
2. 스레드 시작 규칙
   : 스레드를 start()하면 모든 작업은 start() 호출 이후에 실행된 작업보다 happens-before관계가 성립한다.
3. 스레드 종료 규칙
   : 스레드 join()을 하면, 모든 작업은 join()이 반환된 후의 작업보다 happens-before 관계를 가진다.
4. 인터럽트 규칙
   : 스레드 interrupt()호출하는 작업이, 인터럽트된 스레드가 인터럽을 감지하는 시점의 작업보다 happens-before관계를 가진다.
     즉, `interrupt()` 호출 후, 해당 스레드의 인터럽트 상태를 확인하는 작업이 happens-before 관계에 있다.

5. 객체 생성 규칙
6. 모니터 락 규칙
7. 전이 규칙

 

 


출처 : https://inf.run/NC7kS

 

김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성 강의 | 김영한 - 인프런

김영한 | 멀티스레드와 동시성을 기초부터 실무 레벨까지 깊이있게 학습합니다., 국내 개발 분야 누적 수강생 1위, 제대로 만든 김영한의 실전 자바[사진][임베딩 영상]단순히 자바 문법을 안다?

www.inflearn.com

'JAVA' 카테고리의 다른 글

중첩 클래스  (0) 2024.12.22
동시성 문제와 동기화(synchronized)  (0) 2024.11.24
스레드와 Yield  (0) 2024.11.18
스레드 인터럽트  (0) 2024.10.31
스레드 _ JOIN  (0) 2024.10.29