OS

동기화 - synchronized (동시성 이슈)

데일리코딩 2024. 9. 10. 23:00

* 해당 포스팅은 김영한님의 자바 고급편 강의를 완강 후 저만의 방식으로 정리한 내용입니다. 

 

안녕하세요 지난 포스팅에는 메모리 가시성에 대해 이야기하고 어떤 문제를 가지고 있는지

그리고 메모리 가시성 문제를 자바에서는 어떻게 해결하는지 알아보았습니다.

 

오늘은 메모리 가시성 문제보다 더 큰 문제인.. 동기화라는 주제에 대해 이야기 해보고자합니다.

 


동기화 synchronized

OS 카테고리 Java 프로세스와 스레드 포스팅 편에서 멀티스레드를 활용하면 성능 최적화를 이뤄낼 수 있다고 했습니다.

https://junghan49.tistory.com/19

 

Java 프로세스와 스레드

* 해당 포스팅은 김영한님의 자바 고급 편에 있는 멀티스레드 영상을 보고 정리한 내용입니다. 개요처음 자바를 학습할때 이 코드 제일 먼저 보지 않나요?public static void main(String[] args) { //처음

junghan49.tistory.com

 

해당 포스팅에서도 언급했지만 다시 말씀드리자면 멀티스레드에 대해 잘 모르고 사용하면 엄청난 버그를 만날 수 있다고 했습니다.

과연 어떤 문제때문에 엄청난 버그라고 호들갑 떠는지 한번 확인해보도록 하겠습니다.


동시성 이슈

멀티스레드를 사용할 때 가장 주의해야할 점은, 같은 자원에 여러 스레드가 동시에 접근할 때 발생하는 동시성 문제입니다.

참고로 여러 스레드가 접근하는 자원을 공유 자원이라고 합니다. 대표적인 공유 자원은 인스턴스의 필드 입니다.

멀티스레드를 사용할 때는 이런 공유 자원에 대하 접근을 적절하게 동기화 해서 동시성 문제가 발생하지 않게 방지하는 것이 중요합니다.

정리하자면 여러 스레드가 동시에 데이터를 읽고 쓰는 과정에서 충돌이 일어나는 현상을 동시성 이슈라고 합니다.


예제를 통한 동시성 이슈 확인하기

위에 동시성 이슈라는 주제로 텍스트로 설명했지만 아마 처음으로 접하는분들에게는 생소한 내용이라고 생각합니다 

간단한 출금 로직을 통해 어떤 문제가 있는지 확인해보도록 하겠습니다.

 

1. t1, t2 스레드가 존재한다고 가정합니다. 스레드의 작업은 출금하는 로직을 실행합니다.

2. 출금 로직에는 먼저 잔액을 확인해서 출금금액보다 크다면 return false 를 반한합니다.

3. 만약 잔액이 출금금액보다 크다면 기존 잔액에서 출금금액을 빼고 return true 를 반한합니다.

 

먼저 t1이 약간 빨리 먼저 실행했습니다.

이때 잔액이 출금 액수보다 많은지 확인합니다.

출금액이 [800]이 잔액 [1000] 보다 작으므로 검증 로직을 통과합니다.

 

여기서 문제는 t1은 이제 sleep() 함수를 만나 대시상태에 들어갔고 

t2 스레드는 검증로직을 확인하는데 아직 잔액이 1000이고 출금액수는 800이기에 검증 로직이 통과된다

 

t1 스레드에서 검증을 통과하고 잔액에서 출금액 만큼 빼고 잔액은 200원이 된다.

t2 스레드는 이미 검증로직에서는 문제가 없었기 때문에 잔액검증 로직에서 통과하고
우리가 원치않는 마이너스 통장으로 만들어버렸다.
(데이터 일관성 무너짐)

최종적으로 비지니스 검증 로직은 실패했고 데이터 일관성이 무너져 시스템의 신뢰성이 떨어짐

 

이처럼 여러 스레드가 동시에 특정 공유자원에 달려들때 데이터 일관성이 무너지는 문제를 확인할 수 있습니다.

 

이런 동시성 문제를 해결하기 위해서 자바에서는 모든 객체에는 모니터락 이라는 개념이 존재합니다.

동시에 여러 스레드가 공유자원 (객체의 필드) 값을 접근하려는 것을 막고 한개의 스레드만이 점유해서 읽기, 쓰기 가 충돌하지 않도록 예방하는 작업을 할 수 있습니다

 

오늘은 이렇게 동시성 이슈가 무엇인지 알아보았습니다 다음 포스팅에서는 어떻게 동시성 이슈를 해결할 수 있을지 알아보도록 하겠습니다

감사합니다.