본문 바로가기
Java

🔎 synchronized는 정말 동기화를 해주는가?

by sangyunpark99 2024. 7. 19.

synchronized 키워드를 사용하면, 멀티 스레드 환경에서 Race Condition을 해결해주는 지 확인해보자.

 

Q. Race Condition이란?

여러 스레드 또는 프로세스가 동시에 실행되면서 동일한 자원에 접근하거나 변경을 시도할 때 발생하는 문제이다.

프로그램의 동작이나 결과는 실행 순서에 따라 달라질 수 있으며, 예상치 못한 버그나 비정상적인 동작을 유발할 수 있다.

 

@Test

package com.example.payment.test;

import static org.assertj.core.api.Assertions.*;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.jupiter.api.Test;

public class synchronizedTest {

    private int value = 0;

    public void increase() {
        value += 1;
    }

    @Test
    void 동기화_처리_안한_경우() throws Exception{
        //given
        ExecutorService service = Executors.newCachedThreadPool();
        CountDownLatch latch = new CountDownLatch(100);

        //when
        for(int i = 0; i < 100; i++) {
            service.submit(() -> {
                try {
                    increase();
                } finally {
                    latch.countDown();
                }
            });
        }

        //then
        assertThat(value).isEqualTo(100);
    }
}

 

@Test 출력 결과

 

100번 increase 메서드를 호출했는데, 100이 출력되는 것이 아닌, 74가 출력되었다. 멀티 스레드로 increase() 메서드를 호출해주기 때문에 동시성 문제가 발생했다.

Synchronized 키워드 적용

package com.example.payment.test;

import static org.assertj.core.api.Assertions.*;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.jupiter.api.Test;

public class synchronizedTest {

    private int value = 0;

    public synchronized void increase() {
        value += 1;
    }

    @Test
    void 동기화_처리_안한_경우() throws Exception{
        //given
        ExecutorService service = Executors.newCachedThreadPool();
        CountDownLatch latch = new CountDownLatch(100);

        //when
        for(int i = 0; i < 100; i++) {
            service.submit(() -> {
                try {
                    increase();
                } finally {
                    latch.countDown();
                }
            });
        }

        latch.await();

        //then
        assertThat(value).isEqualTo(100);
    }
}

 

@Test 출력 결과

아래 테스트 결과는 동기화 처리를 한 후에 돌린 테스트 결과이다.

 

synchronized 키워드를 통해 공통 변수인 value에 대해 동기화를 해주어서, 올바른 테스트 결과가 나오게 되었다.