[java] 레이스 컨디션(Race Condition)과 스레드 동작 순서

레이스 컨디션 (Race Condition)

레이스 컨디션(Race Condition)은 멀티스레드 환경에서 발생할 수 있는 동시성 문제입니다. 레이스 컨디션은 여러 스레드가 공유된 자원에 동시에 접근하여 값을 변경하려고 할 때 발생합니다. 이때 어떤 스레드가 먼저 자원에 접근하느냐에 따라 예상치 못한 결과가 발생할 수 있습니다.

예시 코드

아래는 레이스 컨디션을 보여주는 간단한 예시 코드입니다.

public class Counter {
    private int count = 0;
    
    public void increment() {
        count++;
    }
    
    public int getCount() {
        return count;
    }
}

public class RaceConditionDemo {
    public static void main(String[] args) {
        Counter counter = new Counter();
        
        Runnable runnable = () -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        };
        
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);
        
        thread1.start();
        thread2.start();
        
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Count: " + counter.getCount());
    }
}

위 코드는 Counter 클래스에서 count 변수를 갖고 있으며, increment() 메소드로 값을 증가시킵니다. RaceConditionDemo 클래스에서는 두 개의 스레드를 생성하여 increment() 메소드를 호출하는데, 이때 count 변수에 대한 접근은 동시에 이루어집니다.

두 스레드가 동시에 increment() 메소드를 호출하면, count 변수가 동시에 증가하는 상황이 발생할 수 있습니다. 이로 인해 실제로 예상한 결과와 다른 값이 출력될 수 있습니다.

스레드 동작 순서

레이스 컨디션 문제는 스레드의 동작 순서에 따라 발생할 수 있습니다. 동시에 접근할 때 순서에 따라 값이 달라지는 것을 방지하려면 동기화(synchronization)를 사용해야 합니다.

위 예시 코드에서는 synchronized 키워드를 이용하여 increment() 메소드를 동기화하고 있습니다. 동기화를 사용하면 한 스레드가 increment() 메소드를 실행하는 동안 다른 스레드는 대기 상태에 있게 됩니다.

public synchronized void increment() {
    count++;
}

이와 같이 동기화를 사용하면 스레드들이 순차적으로 increment() 메소드를 호출하게 되므로 레이스 컨디션 문제를 방지할 수 있습니다.

참고 자료