JavaRush /Java Blog /Random-KO /실제 확률 이론 또는 Random에 대해 알고 계십니까?
Viacheslav
레벨 3

실제 확률 이론 또는 Random에 대해 알고 계십니까?

Random-KO 그룹에 게시되었습니다
실제 확률 이론 또는 Random에 대해 알고 계십니까 - 1

소개

세상에는 확률 이론을 연구하는 많은 과학이 있습니다. 그리고 과학은 다양한 섹션으로 구성됩니다. 예를 들어, 수학에는 무작위 사건, 수량 등을 연구하는 별도의 섹션이 있습니다. 그러나 과학은 가볍게 여겨지지 않습니다. 이 경우 확률 이론은 사람들이 확률 게임을 할 때 주사위를 던지는 데 어떤 패턴이 있는지 이해하려고 노력하면서 구체화되기 시작했습니다. 자세히 살펴보면 우리 주변에는 무작위로 보이는 것들이 많이 있습니다. 그러나 모든 무작위가 완전히 무작위는 아닙니다. 그러나 이에 대해서는 나중에 자세히 설명합니다. Java 프로그래밍 언어는 JDK의 첫 번째 버전부터 난수를 지원합니다. Java의 난수는 java.util.Random 클래스를 사용하여 사용할 수 있습니다 . 테스트를 위해 tutorialspoint java 온라인 컴파일러를 사용합니다 . 다음은 러시아어로 "주사위", 즉 큐브 던지기를 에뮬레이션하기 위해 Random을 사용하는 원시적인 예입니다 .
import java.util.Random;

public class HelloWorld{
    public static void main(String []args){
        Random rnd = new Random();
        int number = rnd.nextInt(6) + 1;
        System.out.println("Random number: " + number);
    }
}
이것으로 Random 설명이 끝날 것 같지만 , 그렇게 간단하지는 않습니다. Java API의 java.util.Random 클래스 에 대한 설명을 열어보겠습니다 . 그리고 여기서 우리는 흥미로운 것을 봅니다. Random 클래스는 의사 난수를 사용합니다. 어떻게요? 난수가 그렇게 무작위가 아니라는 것이 밝혀졌습니다.
실제 확률 이론 또는 Random - 2에 대해 알고 계십니까?

의사 무작위성 java.util.Random

java.util.Random 클래스 에 대한 문서에서는 Random 인스턴스가 동일한 시드 매개변수로 생성되고 동일한 작업 시퀀스가 ​​해당 인스턴스에서 수행되면 동일한 숫자 시퀀스를 반환한다고 나와 있습니다 . 자세히 살펴보면 Random에는 실제로 값을 시드 로 취하는 생성자가 있음을 알 수 있습니다.
Random rnd1 = new Random(1L);
Random rnd2 = new Random(1L);
boolean test = rnd1.nextInt(6) == rnd2.nextInt(6);
System.out.println("Test: " + test);
이 예는 true를 반환합니다 . 두 인스턴스의 시드는 동일합니다. 무엇을 해야 할까요? 기본 생성자는 문제를 부분적으로 해결합니다. 다음은 Random 생성자 의 내용에 대한 예입니다 .
public Random() {
	this(seedUniquifier() ^ System.nanoTime());
}
기본 생성자는 비트 배타적 OR 연산을 사용합니다 . 그리고 현재 시간을 나타내는 long 과 이에 대한 일부 시드를 사용합니다 .
private static long seedUniquifier() {
	for (;;) {
		long current = seedUniquifier.get();
		long next = current * 181783497276652981L;
		if (seedUniquifier.compareAndSet(current, next))
			return next;
	}
}
여기서 또 다른 흥미로운 점은 seedUniquifier getter 메소드를 호출할 때마다 seedUniquifier 값이 변경된다는 것입니다 . 즉, 클래스는 가능한 한 효율적으로 난수를 선택하도록 설계되었습니다. 그러나 문서에 따르면 " 암호적으로 안전하지 않습니다 ". 즉, 암호화 목적(비밀번호 생성 등)을 위한 일부 사용 목적에는 적합하지 않습니다. 적절한 접근 방식의 순서가 예측됩니다. 인터넷에는 이 주제에 대한 예가 있습니다. 예를 들면 다음과 같습니다: " Java에서 다음 Math.random() 예측하기 ". 또는 예를 들어 소스 코드는 " Vulnerability Weak Crypto "입니다. java.util.Random (난수 생성기)에는 특정 “단축키”, Math.random을 통해 실행되는 호출의 단축 버전이 있습니다.
public static void main(String []args){
	int random_number = 1 + (int) (Math.random() * 6);
	System.out.println("Value: " + random_number);
}
그러나 주의 깊게 살펴보면 동일한 Random이 내부에 있습니다.
public static double random() {
	return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}
private static final class RandomNumberGeneratorHolder {
	static final Random randomNumberGenerator = new Random();
}
JavaDoc에서는 " 암호적으로 안전한 의사 난수 생성기 "에 SecureRandom 클래스를 사용할 것을 권장합니다 .
실제 확률 이론 또는 Random - 3에 대해 알고 계십니까?

보안 무작위 Java

SecureRandom 클래스는 java.util.Random 의 하위 클래스 이며 java.security 패키지 에 있습니다 . 이 두 클래스의 비교는 " java.util.Random과 java.security.SecureRandom의 차이점 " 기사에서 읽을 수 있습니다 . SecureRandom이 왜 그렇게 좋은가요? 사실 그에게 난수의 근원은 "핵심 엔트로피 풀"과 같은 마술처럼 들리는 것입니다. 이것은 플러스이자 마이너스입니다. " java.security.SecureRandom의 위험 " 기사에서 이에 대한 단점을 읽을 수 있습니다 . 간단히 말해서 Linux에는 커널 난수 생성기(RNG)가 있습니다. RNG는 키보드 및 디스크 타이밍, 마우스 움직임, 인터럽트 및 네트워크 트래픽과 같은 시스템의 무작위 이벤트를 기반으로 채워지는 엔트로피 풀의 데이터를 기반으로 난수를 생성합니다. 엔트로피 풀에 대한 자세한 내용은 " Linux(RNG)의 난수 또는 /dev/random 및 /dev/urandom을 "채우는" 방법 " 자료에 설명되어 있습니다 . Windows 시스템에서는 sun.security.provider.SecureRandom에 구현된 SHA1PRNG가 사용됩니다. Java가 개발되면서 SecureRandom도 변경되었습니다. 이는 전체 그림을 보려면 " 2016년 4월 현재 Java SecureRandom 업데이트 " 리뷰에서 읽어 볼 가치가 있습니다.
실제 확률 이론 또는 Random - 4에 대해 알고 계십니까?

멀티스레딩 또는 Caesar와 비슷해짐

Random 클래스 의 코드를 보면 문제를 나타내는 것이 아무것도 없는 것 같습니다. 메소드는 동기화로 표시되지 않습니다 . 하지만 한 가지가 있습니다. 여러 스레드에서 기본 생성자를 사용하여 Random을 생성할 때 우리는 그들 사이에 동일한 인스턴스 시드를 공유하여 Random 생성 됩니다 . 또한 새로운 난수를 수신하면 인스턴스 내부 AtomicLong 도 변경됩니다 . 한편으로는 논리적인 관점에서 볼 때 이것은 아무런 문제가 없습니다. 왜냐하면... AtomicLong 이 사용됩니다 . 반면에 생산성을 포함한 모든 것에 대한 비용을 지불해야 합니다. 그리고 이것도 마찬가지입니다. 따라서 java.util.Random 에 대한 공식 문서에서도 다음과 같이 말합니다. " java.util.Random 인스턴스는 스레드로부터 안전합니다. 그러나 스레드 간에 동일한 java.util.Random 인스턴스를 동시에 사용하면 경합이 발생하여 결과적으로 성능이 저하될 수 있습니다. 대신 멀티스레드 디자인에서 ThreadLocalRandom을 사용합니다 ." 즉, 다중 스레드 애플리케이션에서 여러 스레드의 Random을 적극적으로 사용하는 경우 ThreadLocalRandom 클래스를 사용하는 것이 더 좋습니다 . 사용법은 일반 Random 과 약간 다릅니다 .
public static void main(String []args){
	int rand = ThreadLocalRandom.current().nextInt(1,7);
	System.out.println("Value: " + rand);
}
보시다시피, 우리는 이에 대한 시드를 지정하지 않습니다 . 이 예는 Oracle: Concurrent Random Numbers 공식 튜토리얼에 설명되어 있습니다 . 이 클래스에 대한 자세한 내용은 리뷰: " Java의 ThreadLocalRandom 가이드 "에서 읽을 수 있습니다.
실제 확률 이론 또는 Random - 5에 대해 알고 계십니까?

StreamAPI 및 무작위

Java 8이 출시되면서 많은 새로운 기능이 추가되었습니다. 스트림 API를 포함합니다. 그리고 이러한 변화는 Random 값 생성에도 영향을 미쳤습니다 . 예를 들어 Random 클래스에는 , 또는 와 같은 임의의 값을 가진 스트림을 얻을 수 있는 새로운 메서드가 있습니다 . 예를 들어: intdoublelong
import java.util.Random;

public class HelloWorld{
    public static void main(String []args){
        new Random().ints(10, 1, 7).forEach(n -> System.out.println(n));
    }
}
새로운 클래스 SplittableRandom 도 있습니다 .
import java.util.SplittableRandom;

public class HelloWorld{
    public static void main(String []args){
        new SplittableRandom().ints(10, 1, 7).forEach(n -> System.out.println(n));
    }
}
SplittableRandom 과 다른 클래스 간의 차이점에 대한 자세한 내용은 " Java에서 난수를 생성하는 다양한 방법 "에서 확인할 수 있습니다.

결론

결론을 내릴 가치가 있다고 생각합니다. 사용된 클래스에 대한 JavaDoc을 주의 깊게 읽어야 합니다. 언뜻 보면 Random처럼 단순한 것 뒤에는 잔인한 농담을 할 수 있는 뉘앙스가 있습니다. #비아체슬라프
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION