ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ThreadLocalRandom을 왜 사용해야할까?
    스터디/JAVA 2023. 11. 1. 23:51
    728x90

    Random 클래스가 난수를 생성하는 방법

    Random 클래스는 시드를 기반으로 난수를 생성합니다. 즉, 동일한 시드를 사용하면 동일한 난수를 반환합니다.

    하지만 난수라는 개념 자체가 예측할 수 없는 값을 의미하므로, 동일한 시드에서 동일한 난수를 반환하는 것은 진정한 난수 생성과는 다소 거리가 있습니다. 이를 해결하기 위해, Random 클래스는 한 번 사용한 시드를 바탕으로 새로운 시드(newSeed)를 생성하여 다음 난수의 기반이 되도록 합니다.

    protected int next(int bits) {
        AtomicLong seed = this.seed;
    
        long oldseed;
        long nextseed;
        do {
            oldseed = seed.get();
            nextseed = oldseed * 25214903917L + 11L & 281474976710655L;
        } while(!seed.compareAndSet(oldseed, nextseed));
    
        return (int)(nextseed >>> 48 - bits);
    }

     

     

    CAS(Compare-And-Swap) 연산을 사용하여 현재 사용하려는 시드(oldSeed)가 다른 곳에서 이미 사용되었는지를 확인합니다. 만약 oldSeed가 다른 곳에서 변경되었다면, 이는 CPU 캐시 메모리의 시드 값과 RAM에 저장된 시드 값이 달라졌다는 의미이며, 즉 해당 시드가 이미 난수 생성에 사용되었음을 뜻합니다. 따라서 난수의 예측 가능성을 방지하기 위해, while문을 반복합니다.

    경쟁 상태 발생

    수백만 개의 요청이 동시에 들어온다고 가정하고, Random 클래스를 사용하여 난수를 생성한다고 하자. 이 경우, 수많은 요청 중 일부가 동일한 시드(seed)를 부여받을 확률이 높아집니다. 따라서 동일한 시드가 다른 곳에서 먼저 사용될 가능성도 커집니다.

    이렇게 되면, 여러 스레드가 동시에 난수를 생성하려 할 때 동일한 시드를 사용하려고 시도하면서, CAS(Compare-And-Swap) 연산이 반복적으로 실패할 수 있습니다. 결과적으로, 여러 스레드가 반복적으로 while 루프를 돌며 새로운 시드를 찾는 상황이 발생할 수도 있습니다.
    그렇게 되면... 아주 힘든 상황이 발생할 것이다. 🥹


    Java에서는 이러한 상황을 고려하여 ThreadLocalRandom이라는 클래스를 만들었습니다.

    ThreadLocalRandom을 사용하자

     

    ThreadLocalRandom 클래스는 Random 클래스에 발생할 수 있는 경쟁 상태를 해결하기 위해 각 스레드마다 생성된 인스턴스에 각각 seed를 설정해둡니다. 이렇게 하면 멀티 스레드 환경에서 동시에 난수를 발행한다고 해도 각 스레드마다 다른 seed를 사용하기 때문에 경합 문제도 발생하지 않고 난수도 생성할 수 있게 됩니다.

     

    지금까지 Random 클래스에서 발생할 수 있는 문제와 그 해결책인 ThreadLocalRandom 클래스에 대해서 알아보았습니다.
    감사합니다.

    728x90
Designed by Tistory.