본문 바로가기

CS

[JAVA] - 동시성

참고 출처 : 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