우테코에서 제공하는 Randoms.pickNumberInRange()의 동작원리 (feat. ThreadLocalRandom)

Hanjmo·2023년 10월 19일
1

우아한테크코스 프리코스 1주차 미션인 숫자 야구 게임에서 난수를 생성하기 위해 Randoms API를 사용하라는 요구사항을 발견했다.
내가 평소에 난수를 생성하기 위해 사용했던 java.util.Random과 무엇이 다른지 궁금해서 동작 원리를 가볍게 살펴봤다.

Randoms.pickNumberInRange()

아래는 Randoms 클래스의 pickNumberInRange()의 구현부다.

파라미터로 범위의 시작(startInclusive)과 끝(endInclusive)을 나타내는 정수를 받는 것을 확인할 수 있다.

메서드가 호출되면 가장 먼저 파라미터로 넘어온 startInclusive와 endInclusive를 다음과 같이 검증한다.

검증 메서드에서는 범위의 시작이 끝보다 클 때와 끝이 최대로 나타낼 수 있는 정수값과 같을 때, 그리고 범위가 너무 클 때 예외를 발생시킨다.

다시 돌아가서 파라미터 검증 후 값을 반환하는 부분을 보자.
return startInclusive + defaultRandom.nextInt(endInclusive - startInclusive + 1);

이는 시작점과 defaultRandom.nextInt()를 더한 값을 반환한다는 것을 의미한다. 이를 통해 범위의 시작과 끝이 1, 9라고 가정할 때 ‘1 + 0~8’, 즉 "‘1~9’를 반환하겠구나"라고 대충 짐작할 수는 있을 것이다.

그래도 궁금하다.. defaultRandom.nextInt()는 뭐하는 친구일까?

defaultRandom.nextInt()

Randoms 클래스가 가진 defaultRandom은 ThreadLocalRandom.current()에서 반환된 값을 담고 있다.

ThreadLocalRandom...? 타입이 Random이라는 것과 클래스 이름을 봐서는 Random을 상속한 친구인 듯 하다..

그냥 넘어갈 수는 없어 공식문서를 통해 ThreadLocalRandom이 무엇인지부터 알아봤다.

으음.. ThreadLocalRandom은 Random 클래스의 동시성 문제를 해결하기 위해서 사용하는 클래스라고 한다.
멀티 스레드 환경에서 Random API를 사용하면 경합 문제가 발생할 수 있는데, 이를 해결하기 위해 각 스레드마다 생성된 인스턴스에서 난수를 반환하여 안전하다는 이점이 존재한다. (아직 멀티 스레드, 동시성 문제에 대한 개념은 추후에 다루겠다..😇)

그리고 이 ThreadLocalRandom의 current()는 현재 스레드의 ThreadLocalRandom을 반환하는 메서드다.

결국 defaultRandom은 현재 스레드의 ThreadLocalRandom임을 의미하고, defaultRandom.nextInt(n)는 0과 n 사이의 의사 난수를 반환하는 친구임을 알게 되었다.

정리

지금까지 알게 된 내용을 바탕으로 Randoms.pickNumberInRange()의 동작 원리를 정리하자.

특정 범위의 최소값(startInclusive)과 최대값(endInclusive)을 파라미터로 받아온 뒤, 이 두 숫자를 검증한다. 예를 들어 최소값 위치에 최대값보다 큰 숫자가 있는 것은 아닌지 등등..

검증이 성공적으로 끝나면 startInclusive와 defaultRandom.nextInt()를 더한 결과를 반환한다.

이때 defaultRandom.nextInt()에 endInclusive에서 startInclusive를 빼고 1을 더한 값을 넣는 이유는 java.util.concurrent.ThreadLocalRandomnextInt()가 0부터 n 미만의 난수를 생성하기 때문이다.

그래서 1, 9를 파라미터로 넘겨주게 되면, 1부터 9까지의 난수를 반환하는 것이다.

출처

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadLocalRandom.html

https://velog.io/@sojukang/Random-대신-ThreadLocalRandom을-써야-하는-이유

0개의 댓글