참고 출처 : https://www.youtube.com/watch?v=ktWcieiNzKs
동시성 문제
- 한번에 여러 요청(동시적인 반복 요청 포함)이 오거나, 여러 쓰레드가 공유자원을 사용하면 실행 결과가 달라짐
- 따라서, 동시에 중복 요청 혹은 여러 요청에 대해 대비해야함
- 쓰레드 안전한 객체 : 여러 쓰레드가 동시에 클래스를 사용하는 상황에서, 클래스 내부의 값을 안정적인 상태로 유지하는 객체
상황 1.
은행 어플에서 사용자가 실수로 '송금' 버튼을 2번 클릭하는 경우, 서버에서는 해당 요청에 대해 2번 동작해주면 안됨. ( 동시 요청에 대해 1번만 동작해줘야함)
상황 2.
1. A라는 Bool 변수가 있고, B 쓰레드가 있다.
2. B쓰레드는 while문의 조건에서 A 변수의 값을 보고있고, 만약, 값이 바뀌면 while을 탈출.
3. 이때, A 변수의 값이 변경되도, B는 while문을 탈출하지 못함.
- 이유
메모리에 있는 A 변수가 Main 쓰레드의 CPU Cache에 담기고, A변수가 변경됨. 하지만 B쓰레드의 CPU Cache는 바뀌기 전 메모리에 있는 A 변수만을 참조하고 있다. 따라서, A 변수의 변화는 Main 쓰레드의 Cache에서만 일어나기 때문이다.
- 해결법
1. volatile
- 접근 제한자와 리턴 변수형 사이에 volatile 삽입. (예, public volatil static void ....)
- volatile을 사용하면, 쓰레드가 CPU Cache 대신 메모리에서 읽어 온다.
2. Synchronized( 블로킹 방식 - Mornitor 방식)
- 블로킹 : 특정 쓰레드가 작업 수행 중 -> 대기
- 배타동기큐 -> 임계영역 -> 조건동기큐
- volatile과 같이 접근제한자와 리턴 변수형 사이에 삽입 (public synchronized void .... )
1. 공유 자원을 사용해야하는 여러 쓰레드들을 일단 배타동기큐에 담음.
2, 들어온 순서대로 하나씩 임계영역에 넣어줌.
3. 실행 중 wait()을 만나면 쓰레드는 조건동기큐에 삽입되고, 다음 쓰레드가 임계영역에 들어옴.
4. 다른 쓰레드가 notify(), notifyAll()과 같은 메서드를 만나면, 조건동기큐에 있던 쓰레드와 교체.
- 블로킹 방식의 단점
1. 하나의 쓰레드만 임계구역에 들어가 작업이 가능 ➡️ 나머지 쓰레드들은 대기 ➡️ 성능 저하
2. 임계구역에 들어갈 때, 락(Lock) ➡️ 데드락 발생 가능
3. Atomic Type ( 논 블로킹 방식 )
- 논블로킹 : 다른 쓰레드들과 상관 없이 자신의 작업을 수행
- 자바에서 동시성을 지원하기 위해 제공하는 래퍼 클래스
- Integer ➡️ AtomicInteget / Long ➡️ AtomicLong 과 같이 사용
- 내부의 Volatile로 가시성을 보장, CAS를 통해 원자성을 보장
* CAS (Compare And Set) 알고리즘
1. 자원 값(레퍼런스)을 가져올 때, Value를 복사한 기댓값을 생성 후 자원 값을 이용해 연산.
2. 연산 후, 자원 값과 기댓값을 비교.
3-1. 만약, 자원 값이 변경되어 (다른 쓰레드에서 자원 값을 수정하여) 기댓값과 다르면, 변경된 자원값으로 재연산 후 다시 확인
3-2. 만약, 자원 값이 기댓값과 같으면, 연산 결과를 자원 값에 반영.
쓰레드 안전한 객체를 위한 설계
1. 공유 변수를 최소화 ➡️ 근본적인 원인을 해결
2. 공유 변수 한 객체에 캡슐화 ➡️ 한 곳에서 관리
3. 공유 변수에 대한 동기화 코드들을 문서화
'CS' 카테고리의 다른 글
자료 구조 - 트리 구조 정리 (0) | 2024.03.07 |
---|---|
운영체제 - 기초 (0) | 2024.03.07 |
[DB] 트랜잭션(Transaction)이란? (0) | 2023.05.09 |
[DB] OUTER JOIN 정리 (0) | 2023.03.24 |
[DB] INNER JOIN 정리 (0) | 2023.03.24 |