-
🆚 Random 함수 비교☕️ java 2023. 10. 23. 12:36
숫자야구 프로그램을 만들면서 Java에서 제공하는 Random 함수들이 어떤 것들이 있는지 궁금하고 어떤 것을 사용해야할지 궁금했다.
1️⃣ java.util.Random
💡 java.util 패키지에 있는 Random 클래스를 사용하는 방법
- 인스턴스를 생성해서 사용🖥️ 사용
- 2가지 객체 생성 방법
- 기본 생성자를 사용하는 방법
- long 타입의 시드를 인자로 받는 생성자를 사용하는 방법
// 기본 생성자 Random random = new Random(); // long 타입의 시드를 인자로 받는 생성자 Random random = new Random(10); // 난수 범위 지정 int randomNumber = random.nextInt(max - min) + min;
⚠️ 주의할 점
- long 타입의 seed 값을 설정해 Random 클래스를 사용할 때 주의할 점이 존재
for (int i = 0; i < 5; i++) { Random random = new Random(10); for (int j = 0; j < 5; j++) { System.out.print(random.nextInt() + " "); } System.out.println(); }
결과
-1157793070 1913984760 1107254586 1773446580 254270492 -1157793070 1913984760 1107254586 1773446580 254270492 -1157793070 1913984760 1107254586 1773446580 254270492 -1157793070 1913984760 1107254586 1773446580 254270492 -1157793070 1913984760 1107254586 1773446580 254270492
동일한 seed 값을 갖는 인스턴스가 생성한 난수는 일정 패턴을 가지게 된다…!
🤔 why?
유사 난수 생성기(pseudo-random-generator)를 통해 실제로 무작위가 아닌 일련의 숫자를 생성하게 된다.
public Random(long seed) { if (getClass() == Random.class) this.seed = new AtomicLong(initialScramble(seed)); else { // subclass might have overridden setSeed this.seed = new AtomicLong(); setSeed(seed); } } private static long initialScramble(long seed) { return (seed ^ multiplier) & mask; }
- 특정 알고리즘으로 생성된 값을 반환하게 되는 것이다.
❗ seed 값을 설정하지 않은 경우는 현재 시간을 활용한다.
public Random() { this(seedUniquifier() ^ System.nanoTime()); }
⚠️ 멀티 쓰레드에서 위험
java.util.Random 은 멀티 쓰레드에서 하나의 Random 인스턴스를 공유하여 전역으로 사용된다.
이때, 같은 시간에 멀티 쓰레드에서 요청이 들어온다면❓
- 같은 난수를 반환하지는 않는다.
- 하지만, 여러 쓰레드가 경합을 하는 과정을 반복하게 되어 성능상의 문제가 발생할 수 있다.
2️⃣ Math.random 메서드
💡 Math.random 메서드는 객체 생성 없이 바로 사용할 수 있는 정적 메서드
📍 반환 값
- 0.0 ≤ .. ≤ 1.0 보다 작은 double 형 값
- 현재 시간을 seed 값 으로 사용해 매 실행마다 다른 난수가 반환된다.
🖥️ 사용
// 0.0보다 크거나 같고 1.0보다 작은 값 double randomNumber = Math.random(); // min값보다 크거나 같고 max값보다 작은 난수 int randomNumber = (int) (Math.random() * (max - min)) + min);
📖 정적 메서드
- 인스턴스 생성 없이 호출 가능
3️⃣ ThreadLocalRandom
💡 ThreadLocalRandom
- 현재 스레드에 격리된 난수 생성기
- ThreadLocal 클래스와 Random 클래스의 조합
- java.util.concurrent.ThreadLocalRandompublic class ThreadLocalRandom extends Random { ... public void setSeed(long seed) { // only allow call from super() constructor if (initialized) throw new UnsupportedOperationException(); } ... }
💡 특징
- Math.random 메서드와 마찬가지로 수정할 수 없는 내부 생성 seed 로 초기화
- setSeed 메서드를 재정의하여 호출된 경우 UnsupportedOperationException 예외 호출
- 동시 프로그램에서 Random 클래스를 사용한 것보다 일반적으로 오버헤드와 경합이 적다.
- 스레드 풀에서 난수를 병렬로 사용시 적절
- 암호적으로 안전하지 않다. 보안에 민감한 응용프로그램에서는 SecureRandom을 사용하는 것을 고려
🆚 Random 클래스
다중 스레드 환경에서 두 클래스(Random, ThreadLocalRandom)를 사용해 임의의 값을 생성하고 JMH를 사용해 성능을 비교해보기.
@State(Scope.Benchmark) public class Sample { private static final int N = 1000; @Benchmark public void testRandom(Blackhole blackhole) { Random random = new Random(); for (int i = 0; i < N; i++) { int result = random.nextInt(); blackhole.consume(result); } } @Benchmark public void testThreadLocalRandom(Blackhole blackhole) { for (int i = 0; i < N; i++) { int result = ThreadLocalRandom.current().nextInt(); blackhole.consume(result); } } public static void main(String[] args) throws Exception { org.openjdk.jmh.Main.main(args); } }
결과(results.txt)
Benchmark Mode Cnt Score Error Units Sample.testRandom thrpt 105661.179 ops/s Sample.testThreadLocalRandom thrpt 294349.298 ops/s
- ThreadLocalRandom을 사용했을 경우 더 효율적으로 동작!!
📖 JMH
- JVM 위에서 동작하는 코드의 성능을 측정해주는 라이브러리
- 간단한 코드나 여러 코드의 상대적 성능을 측정할 때 간단히 사용
🖥️ 사용
int randomNumber = ThreadLocalRandom.current().nextInt()); // 1과 10 사이의 난수 int boundedRandomValue = ThreadLocalRandom.current().nextInt(1, 10);
4️⃣ SecureRandom
- java.security.SecureRandom
- 더 강력한 의사난수 생성기를 이용해 난수를 생성
🖥️ 사용
SecureRandom secureRandom = new SecureRandom(); int randomInt = secureRandom.nextInt(); // 1과 10 사이의 난수 randomInt = secureRandom.nextInt(10 - 1) + 1
🆚 Random
- Random 클래스는 시스템 시간을 시드로 사용하거나 시드를 생성
- SecureRandom은 OS의 무작위 데이터를 가져와 시드로 사용한다.
- 48비트를 갖는 Random과 다르게 SecureRandom은 최대 128비트를 포함한다.
- 반복될 확률이 적다.
- 내부에서 다양한 난수 생성과정을 거쳐 Random 클래스보다 느리다
📕 참고자료
ThreadLocalRandom (Java Platform SE 8 )
Guide to ThreadLocalRandom in Java | Baeldung
GitHub - openjdk/jmh: https://openjdk.org/projects/code-tools/jmh
'☕️ java' 카테고리의 다른 글
일급 컬렉션 (1) 2023.10.24 🧪 JMH (Java Microbenchmark Harness) (1) 2023.10.23 DAO DTO / VO (0) 2023.03.10 [Java] 실수 표현 - 고정소수점, 부동소수점 (0) 2023.03.07 BigDecimal ❓ (0) 2023.03.07 - 2가지 객체 생성 방법