2013-10-01 2 views
3

난 임의 수 생성 & 자바의 멀티 스레딩 개념을 배우고 있습니다.특정 타임 스탬프에 대한 고유 난수

아이디어는 특정 밀리 초에서 범위 1000의 반복 된 난수를 생성하지 않는 것입니다 (다중 스레드 방식에서 50 개가 넘지 않는 데이터를 고려하면 밀리 초 단위로 처리됩니다). 따라서 특정 시간에 생성 된 난수 목록은 고유합니다. 당신이 나에게 어떤 아이디어를 줄 수 있을까요? 나는 밀리 초에 몇개의 반복되는 난수를 생성하는 것을 끝낼 것입니다. (또한 상당한 확률이 있습니다.)

나는 내가 실패한 다음과 같은 것들을 시도했다.

Random random = new Random(System.nanoTime()); 
double randomNum = random.nextInt(999); 

//

int min=1; int max=999; 
double randomId = (int)Math.abs(math.Random()* (max - min + 1) + min); 

//

Random random = new Random(System.nanoTime()); // also tried new Random(); 
double randomId = (int)Math.abs(random.nextDouble()* (max - min + 1) + min); 

I 8-10 주위 (I는 동일한 ID를 참조 멀티 스레드 환경에서 생성되는 타임 스탬프를 추가 이대로)가 5000+ 고유 데이터에 대해 생성됩니다 (2-4 회).

+2

:

//create only one Random instance, seed is based on current time public static final Random generator= new Random(); 

지금 모든 스레드는 같은 인스턴스를 사용해야합니까? 코드 일부를 추가하십시오. 문제가 정확히 어디입니까? – bidifx

+1

다른 것을 한 가지 명확히하려는 것이 좋습니다. 예를 들어 멀티 스레딩은 난수 생성과 아무런 관련이 없으므로 혼동해서는 안됩니다. – Ingo

+0

최대 및 최소값은 무엇입니까? – Fildor

답변

2

이 클래스를 사용하면 전체 범위를 사용할 때까지 특정 범위에서 비 반복 값을 얻을 수 있습니다. 범위가 사용되면 다시 초기화됩니다.

클래스는 간단한 테스트와 함께 제공됩니다.

클래스 스레드를 안전하게 만들려면 synchronizednextInt() 선언에 추가하십시오.

그런 다음 싱글 톤 패턴이나 정적 변수를 사용하여 여러 스레드에서 생성기에 액세스 할 수 있습니다. 그렇게하면 모든 스레드가 동일한 객체와 동일한 고유 ID 풀을 사용하게됩니다. 이 like this 보이는 때문에, 당신은 new Random()를 사용해야합니다

public class NotRepeatingRandom { 
    int size; 
    int index; 
    List<Integer> vals; 
    Random gen = new Random(); 

    public NotRepeatingRandom(int rangeMax) { 
     size = rangeMax; 
     index = rangeMax; // to force initial shuffle 
     vals = new ArrayList<Integer>(size); 
     fillBaseList(); 
    } 

    private void fillBaseList() { 
     for (int a=0; a<size; a++) { 
     vals.add(a); 
     } 
    } 

    public int nextInt() { 
     if (index == vals.size()) { 
      Collections.shuffle(vals); 
      index = 0; 
     } 
     int val = vals.get(index); 
     index++;  
     return val; 
    } 

    public static void main(String[] args) { 
     NotRepeatingRandom gen = new NotRepeatingRandom(10); 
     for (int a=0; a<30; a++) { 
      System.out.println(gen.nextInt()); 
     } 
    } 
} 
+2

Ouch - 순진한 구현을 위해, 나는 이것이 어디에서 진행 되는가를 좋아하지만 성능에 약간의 문제가있을 것입니다. 이와 같이 무작위 요소를 끊임없이 제거하면 전체 배열이 쉬프트됩니다 (하나의 요소 ... at ... a ... ... 시간 ...). 'rebuildCurVals()'에'curVals'을 섞은 다음,리스트에서 _last_ 요소를 끊임없이 제거하는 편이 낫습니다. 또는 다른 (아마도 커스텀'Queue' 구현?) 데이터 구조를 사용하는 방법을 살펴보십시오. –

+0

@ Clockwork-Muse 당신이 맞습니다. 최적화의 첫 번째 법칙을 따르는 것에 대해 매우 강하게 느낍니다. "최적화하지 마십시오." 클래스는 잘 캡슐화되어 있으며 그러한 필요성이 발생하면보다 최적의 구현으로 쉽게 대체 될 수 있습니다. – Dariusz

+0

@ Clockwork-Muse하지만 OK, 나는 그 코드가 단순했기 때문에 코드를 최적화했다. – Dariusz

4

먼저 (자세한 내용은 Java 버전에 따라 다릅니다) :

public Random() { this(++seedUniquifier + System.nanoTime()); } 
private static volatile long seedUniquifier = 8682522807148012L; 

즉, 그것은 이미 nanoTime()을 사용하여 같은 nanoTime() 결과를 가진 다른 스레드가 new Random(System.nanoTime())이 아닌 다른 시드를 갖도록합니다.

(편집 : 피 랑하이 자바 6의 버그이지만 in Java 7 고정있어 지적 :

public Random() { 
    this(seedUniquifier()^System.nanoTime()); 
} 

private static long seedUniquifier() { 
    // L'Ecuyer, "Tables of Linear Congruential Generators of 
    // Different Sizes and Good Lattice Structure", 1999 
    for (;;) { 
     long current = seedUniquifier.get(); 
     long next = current * 181783497276652981L; 
     if (seedUniquifier.compareAndSet(current, next)) 
      return next; 
    } 
} 

private static final AtomicLong seedUniquifier 
    = new AtomicLong(8682522807148012L); 

)는 1 1000-50 난수를 생성하는 경우,

둘째, 확률 어떤 숫자는 the birthday paradox 덕분에 꽤 똑같습니다.

세 번째로 고유 ID 만 원한다면 난수 대신에 AtomicInteger 카운터를 사용할 수 있습니다. 또는 무작위 부분을 시작하려는 경우 고유성을 보장하기 위해 카운터를 추가하십시오.

+2

이 메커니즘은 스레드로부터 안전하지 않습니다. 두 개의 다른 스레드가 동일한 'seedUniquifier'를 사용할 수 있습니다. 'seedUniquifier'는 volatile이지만'++ 'operator는 * not * atomic입니다. 안전한쪽으로 가지려면, 시드 값이나 적절한 동기화 수단을 유지하기 위해 AtomicInteger 나 AtomicLong을 사용해야합니다. – Pyranja

+0

@Pyranja 좋은 지적입니다. 이것이 Java 7에서 수정 된 이유입니다. AtomicLong을 사용합니다. –

0

질문을 올바르게 이해하면 여러 스레드가 동시에 임의의 클래스의 인스턴스를 만들고 모든 스레드가 동일한 난수를 생성합니까? 모든 임의의 인스턴스가 동시에 생성되었으므로 (즉 동일한 시드로) 동일한 번호가 생성됩니다.

이 문제를 해결하려면 모든 스레드가 동일한 인스턴스에서 nextDouble()을 호출하도록 모든 스레드가 공유하는 임의 클래스의 인스턴스 하나만 생성하십시오. Random.nextDouble() 클래스는 스레드로부터 안전하며 모든 호출에 대해 시드를 암시 적으로 업데이트합니다. 지금까지 시도 무엇

double random=generator.nextDouble() 
관련 문제