Search

[Applicaion]07.동시성 문제 :방안(1) Java Synchronized

Publish Date
2024/11/12
Tags
Status
Done
1 more property
동시성 문제: Java Synchronized
쿠폰 발급 시스템에서 동시성 문제를 해결하기 위해 Java의 synchronized 키워드를 사용하여 단일 스레드 접근을 보장하고, 쿠폰 발급 수량의 일관성을 유지하는 것을 목표로 한다.

배경 및 목표

Java의 synchronized 키워드는 단일 서버 환경에서 동시성 문제를 해결하는 가장 간단한 방법이다. 특정 블록에 대해 하나의 스레드만 접근할 수 있도록 제한하며, 데이터 정합성을 보장한다.synchronized는 자바에서 제공하는 동기화 메커니즘으로, 특정 객체를 기준으로 락을 설정하여 동시에 여러 스레드가 접근하지 못하게 한다.

Synchronized 키워드

구조 및 구현

coupon-BE/ ├── coupon-core/ │ └── src/ │ └── main/java/com/example/couponcore/ │ └── service/ # 비즈니스 로직 처리 계층 │ └── CouponIssueService.java └── coupon-api/ └── src/ └── main/java/com/example/couponapi/ └── service/ # 비즈니스 로직 처리 계층 └── CouponIssueRequestService.java
Java
복사
파일명
내용
CouponIssueService.java
트랜잭션 내부에 synchronized 사용 (잘못된 구조로 동시성 문제 발생)
CouponIssueRequestService.java
synchronized를 트랜잭션 상위에 위치시켜 동시성 문제를 해결한 구조

소스코드

CouponIssueService.java
버전1. 트랜잭션 내부에 Lock 위치(잘못된 구조)
@Transactional 트랜잭션 내부에서 synchronized를 설정하면 동시성 문제를 해결할 수 없다. 트랜잭션의 범위가 동기화 블록과 일치하지 않아 커밋 전에 다른 스레드가 접근할 가능성이 있다.
package com.example.couponcore.service; @RequiredArgsConstructor @Service public class CouponIssueService { @Transactional public void issue(long couponId, long userId) { synchronized (this) { Coupon coupon = findCoupon(couponId); // 쿠폰 조회 coupon.issue(); // 쿠폰 발급 처리 (issuedQuantity++) saveCouponIssue(couponId, userId); // 발급 정보 저장 } }
JavaScript
복사
CouponIssueRequestService.java
버전2. 트랜잭션 외부에 Lock 위치(동시성 문제해결 버전)
@Transactional 외부에 synchronized를 사용하여 동기화 블록의 범위를 트랜잭션 전체로 확장한다. 이를 통해 트랜잭션의 일관성을 유지하면서 동시 접근을 제어할 수 있다.
package com.example.couponapi.service; @RequiredArgsConstructor @Service public class CouponIssueRequestService { ... public void issueRequestV1(CouponIssueRequestDto requestDto) { synchronized(this){ couponIssueService.issue(requestDto.couponId(), requestDto.userId()); } log.info("쿠폰 발급 완료. couponId: %s, userId: %s".formatted(requestDto.couponId(), requestDto.userId())); } }
JavaScript
복사

결론

트랜잭션 상위에 Lock을 위치시키는 구조(버전 2)는 트랜잭션의 범위와 동기화 블록의 범위를 일치시켜 동시성 문제를 해결한다. 하지만 스레드가 하나씩 순차적으로 접근하므로 성능이 제한될 수 있다. 이를 보완하기 위해 Redis 분산 락이나 MySQL 비관적 락(SELECT FOR UPDATE) 같은 다른 동시성 제어 방법도 고려할 필요가 있다.
구분
트랜잭션 내부 Lock
트랜잭션 상위 Lock
Lock 위치
@Transactional 내부 synchronized
@Transactional 외부 synchronized
동시성 문제
여전히 발생할 수 있음
해결됨
트랜잭션 범위
Lock과 트랜잭션 범위가 불일치
Lock과 트랜잭션 범위가 일치
성능
단일 스레드로 처리되나 동기화 범위가 불안정
안정적으로 동기화되나 스레드 블록 발생
Search
Main PageCategoryTagskkogggokkAbout MeContact