랜덤 클래스 스레드는 안전합니까?


110

하나의 인스턴스를 공유하는 것이 유효한가요? Random여러 스레드간에 클래스 합니까? nextInt(int)특히 여러 스레드에서 호출하려면 ?


@Bala R, 아니, 우리는 C #의 Random 객체가 아니라 Java에 대해 이야기하고 있습니다.
Buhake Sindi 2011

죄송합니다. 그 부분을 놓쳐서 죄송합니다.
Bala R

다중 스레드 환경에서 숫자를 얻기 위해 Random을 사용하면 나쁜 결과를 얻을 수 있습니다. 아마 중요하지 않지만 시뮬레이션을 수행하는 경우 알아두면 좋습니다.
Maxence SCHMITT 2011

14
더 많은 독자를 위해 : 1.7이라는 새로운 클래스가 java.util.concurrent.ThreadLocalRandom있습니다.
Jin Kwon

답변:


66

여러 스레드에서 사용할 때 여전히 난수를 생성한다는 점에서 스레드로부터 안전합니다.

Sun / Oracle JVM 구현은 동기화 및 AtomicLong을 시드로 사용하여 스레드 간의 일관성을 향상시킵니다. 그러나 문서의 모든 플랫폼에서 보장되지는 않습니다.

특히 nextInt()호출 될 순서를 결정할 수 없기 때문에 이러한 보증을 요구하도록 프로그램을 작성하지 않습니다 .


69
Java 7 문서에 "java.util.Random의 인스턴스는 스레드로부터 안전합니다."라는 보증이 추가되었습니다. docs.oracle.com/javase/7/docs/api/java/util/Random.html
Matt R



7

예, Random은 스레드로부터 안전합니다. 이 nextInt()메서드 next(int)AtomicLong seed, nextseed(atomic long)을 사용하여 다음 시드를 생성하는 보호 된 메서드를 호출합니다 . AtomicLong시드 생성시 스레드 안전성을 위해 사용됩니다.


6

말했듯이 스레드 저장이지만 이 기사 (링크 데드) java.util.concurrent.ThreadLocalRandom에 따라 사용하는 것이 현명 할 수 있습니다 . ThreadLocalRandom은 Random의 하위 클래스이기도하므로 이전 버전과 호환됩니다.

링크 된 기사는 서로 다른 Random 클래스의 프로파일 링 결과를 비교했습니다 : java.util.Random, java.util.concurrent.ThreadLocalRandomjava.lang.ThreadLocal<java.util.Random>. 결과는 ThreadLocalRandom의 사용이 가장 성능이 뛰어나고 ThreadLocal이 그 다음으로 가장 성능이 좋지 않은 것으로 나타났습니다.


4

여러 스레드가 모두 동일한 Random을 사용할 수없는 이유는 없습니다. 그러나 클래스는 명시 적으로 스레드로부터 안전하지 않으며 시드를 통해 일련의 의사 난수를 유지합니다. 여러 스레드가 동일한 난수로 끝날 수 있습니다. 각 스레드에 대해 여러 개의 Random을 만들고 다르게 시드하는 것이 좋습니다.

편집 : 방금 Sun 구현이 AtomicLong을 사용하므로 스레드로부터 안전하다고 생각합니다 (Peter Lawrey (+1)도 언급했듯이).

EDIT2 : OpenJDK는 또한 시드에 AtomicLong을 사용합니다. 다른 사람들이 말했듯이 이것에 의존하는 것은 여전히 ​​좋지 않습니다.


3

Random이 원자 변수를 사용한다고 가정하지 않고 문제를 처리 한 방법은 다음과 같습니다. currentTime * thread id미래의 시간이 같으면 여전히 무작위로 충돌 할 수 있지만 내 필요에 따라 충분히 드뭅니다. 충돌 가능성을 진정으로 피하려면 각 요청이 고유 한 시계 타임 스탬프를 기다리도록 할 수 있습니다.

/**
 * Thread-specific random number generators. Each is seeded with the thread
 * ID, so the sequence of pseudo-random numbers are unique between threads.
 */
private static ThreadLocal<Random> random = new ThreadLocal<Random>() {
    @Override
    protected Random initialValue() {
        return new Random(
            System.currentTimeMillis() *
            Thread.currentThread().getId());
    }
};

쪽으로! Q : (24*60*60*1000)부분이 중요합니까?
진 권

1
그래, 그건 더러운 수정이었다. 이는 millis의 (24*60*60*1000)ID 12xxxxxxxxxx045가진 스레드 22xxxxxxxxxx035millis 의 스레드와 동일하게 시드되지 않도록하기위한 것 입니다. 그러나 스레드 ID가 증분이라고 가정 할 충분한 이유가 없으며 오늘보다 내일 더 임의의 시간에 스레드를 생성한다고 생각할 타당한 이유가 없습니다. 이제 alg를 단순화하고 단점을 식별하기 위해 설명을 업데이트했습니다.
라이언

0

Random클래스는 다중 스레드에 사용되는 하나의 예를 들어 설정되지 않았습니다. 물론 이렇게하면 예측할 수없고 난수에 가까워 질 가능성이 높아집니다 . 하지만 의사 랜덤 생성기이므로 인스턴스를 공유해야하는 이유를 알 수 없습니다. 더 구체적인 요구 사항이 있습니까?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.