@Transactional๊ณผ synchronized๋ฅผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด ์™œ ์•ˆ ๋ ๊นŒ?

1. ๊ฐœ์š”

ํ”„๋กœ์ ํŠธ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋กœ์ง์ด ์žˆ๋‹ค. ๋ชจ์ง‘ ๊ณต๊ณ ์— ๋ชจ์ง‘ ์ธ์›์„ ์ดˆ๊ณผํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋ชจ์ง‘๋œ ์ธ์›์„ ์ฆ๊ฐ€์‹œ์ผœ ์ฃผ๊ณ  ์žˆ๋‹ค.  

public synchronized void plusRegisteredNum(Integer updateCount) {
    if (this.registeredNum + updateCount > this.recruitNum) {
        throw new CustomException(ErrorCode.APPLY_OVER_RECRUIT_NUM);
    }
    this.registeredNum += updateCount;
}

 

 

๋™์‹œ์„ฑ ์ด์Šˆ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด synchronized ํ‚ค์›Œ๋“œ๋ฅผ ๋„ฃ์–ด์ฃผ์—ˆ๋Š”๋ฐ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ดค์„ ๋•Œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. 

 

์›์ธ์„ ์ฐพ์•„๋ดค๋”๋‹ˆ @Transactional๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์‹œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ํ•œ๋‹ค.

 

์™œ ๊ทธ๋Ÿฐ์ง€ ์ž์„ธํ•˜๊ฒŒ ์•Œ์•„๋ณด์ž. 

 

 

 

 

 

 

2. ๋ฌธ์ œ ์ƒํ™ฉ

@Test
public void ๋™์‹œ์„ฑ_ํ…Œ์ŠคํŠธ() throws InterruptedException {
    int threadCount = 100;
    ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
    CountDownLatch latch = new CountDownLatch(threadCount);

    for (int i = 0; i < threadCount; i++) {
        executorService.submit(() -> {
            try {
                workDateTestService.plusRegisteredNum(1L);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                latch.countDown();
            }
        });
    }

    latch.await();
    executorService.shutdown();

    WorkDate updatedWorkDate = workDateRepository.findById(1L).get();
    assertThat(updatedWorkDate.getRegisteredNum()).isEqualTo(threadCount);
}

 

 

๋ชจ์ง‘ ์ธ์›์„ ์ฆ๊ฐ€์‹œํ‚ค๋Š” api์˜ ๋กœ์ง์€ ๋งŽ์ด ๋ณต์žกํ•ด ํ•ด๋‹น ๊ธฐ๋Šฅ๋งŒ ํ…Œ์ŠคํŠธ ํ•˜๊ธฐ ์œ„ํ•ด TestService๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค. 

@Service
@RequiredArgsConstructor
@Transactional
public class WorkDateTestService {
    private final WorkDateRepository workDateRepository;

    public void plusRegisteredNum(Long workDateId) {
        WorkDate workDate = workDateRepository.findById(workDateId)
                .orElseThrow(() -> new CustomException(ErrorCode.WORK_DATE_NOT_FOUND));

        workDate.plusRegisteredNum(1);
    }
}

 

์œ„ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 

 

 

 

 

 

 

3. ๋ฌธ์ œ ์›์ธ

synchronized๋ฅผ ์‚ฌ์šฉํ–ˆ์Œ์—๋„ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•œ ์ด์œ ๋Š” ํŠธ๋žœ์žญ์…˜์˜ ๋™์ž‘์›๋ฆฌ ๋•Œ๋ฌธ์ด๋‹ค.

 

์‚ฌ์ง„๊ณผ ํ•จ๊ป˜ ์ž์„ธํ•˜๊ฒŒ ์‚ดํŽด๋ณด์ž. 

 

 

@Transaction์ด ์ ์šฉ๋œ ํด๋ž˜์Šค๋Š” CGLIB์— ์˜ํ•ด์„œ ๋Ÿฐํƒ€์ž„์— ํ•ด๋‹น ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ํ”„๋ก์‹œ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  @Transactional ๋กœ์ง์œผ๋กœ ์ง„์ž…ํ•˜๊ธฐ ์ „/ํ›„์—์„œ Transaction Begin & Commit/Rollback์ด ์ง„ํ–‰๋˜๋Š” ๊ฒƒ์ด๋‹ค

 

์ด๋ ‡๊ฒŒ @Transactional์ด ๊ฑธ๋ ค์žˆ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— synchronized ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด๊ฒŒ ๋œ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋™์ž‘ํ•œ๋‹ค

 

 

ํ•ด๋‹น ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— synchronized๊ฐ€ ๊ฑธ๋ ค์žˆ์œผ๋‹ˆ ํ•ด๋‹น ๋กœ์ง์œผ๋กœ ์ง„์ž…ํ• ๋•Œ Monitor Lock์„ ๊ฐ€์ง€๊ณ  ์ง„์ž…ํ•˜๊ฒŒ ๋˜๋Š”๊ฒƒ์ด๋‹ค

 

 

 

๊ทธ๋Ÿฌ๋ฉด Thread1์„ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ์“ฐ๋ ˆ๋“œ๋“ค์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๊ณ  Lock์„ ์–ป๊ธฐ ์œ„ํ•ด์„œ ๋Œ€๊ธฐํ•œ๋‹ค ์—ฌ๊ธฐ์„œ Thread1์ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋๋‚ด๊ณ  ์ปค๋ฐ‹/๋กค๋ฐฑ ์‹œ์ ์œผ๋กœ ๋Œ์ž…ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž

 

 

 

 

์ด ์‹œ์ ์— Thread2๊ฐ€ ์ง„์ž…ํ•˜๊ฒŒ ๋˜๋ฉด ์•„์ง Thread1์˜ ๋กœ์ง์ด commit๋˜๊ธฐ ์ „์ด๋ฏ€๋กœ DB์— ์กด์žฌํ•˜๋Š” Ticket์˜ stock์€ ์—ฌ์ „ํžˆ 100์ด๋‹ค.

๊ทธ์— ๋”ฐ๋ผ์„œ Thread2๋Š” Ticket์˜ stock์„ 100์œผ๋กœ ๋ฐ›๊ฒŒ ๋˜๊ณ  ๊ทธ์— ๋”ฐ๋ฅธ ๋กœ์ง์ด ์ง„ํ–‰๋œ๋‹ค.

 

์ฆ‰ ํŠธ๋žœ์žญ์…˜์ด ์‹œ์ž‘ & ์ปค๋ฐ‹,๋กค๋ฐฑ ๋˜๋Š” ์‹œ์ ์—” Lock์ด ๊ฑธ๋ฆฌ์ง€ ์•Š๊ฒŒ ๋˜๊ณ  ์—ฌ๊ธฐ์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค. 

 

 

 

 

 

 

 

4. ๊ฒฐ๋ก 

synchronized ํ‚ค์›Œ๋“œ๋Š” Java์—์„œ ์Šค๋ ˆ๋“œ ๋™๊ธฐํ™”๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ด์ง€๋งŒ, ํ•œ๊ณ„๊ฐ€ ๋ช…ํ™•ํ•œ ๊ฒƒ ๊ฐ™๋‹ค.

 

์ฒซ ๋ฒˆ์งธ๋กœ ํŠธ๋žœ์žญ์…˜๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์ด๋‹ค. ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ ..~~ ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ๋„ ๋–จ์–ด์งˆ ๋ฟ๋”๋Ÿฌ ํšจ์œจ์ ์ด์ง€ ๋ชปํ•˜๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.

 

๋‘๋ฒˆ์งธ๋กœ ๋ชจ๋“  ์Šค๋ ˆ๋“œ ๋™์ž‘์— ๋Œ€ํ•ด ๋ฝ์„ ๊ฑธ์–ด๋ฒ„๋ ค ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์„ธ๋ฒˆ์งธ๋กœ ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค์—์„œ๋งŒ ๊ฒฉ๋ฆฌ์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‘ ๊ฐœ ์ด์ƒ์˜ ์„œ๋ฒ„์—์„œ๋Š” ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋‹ค.