배경 및 목표
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과 트랜잭션 범위가 일치 |
성능 | 단일 스레드로 처리되나 동기화 범위가 불안정 | 안정적으로 동기화되나 스레드 블록 발생 |
Related Posts
Search