2011-01-25 8 views
4

私はnoncesを生成するために新しいRandom()。nextLong()を呼び出すOAuthライブラリを使用していますが、非同期呼び出しで同じnonceを生成します。私はRandom.nextLong()をスレッシュすることで、同じ正確な数値を頻繁に返すように絞り込んだ。JavaスレッドRandom.nextLong()同じ番号を返す

これはJavaの既知の制限事項は誰にも分かりますか?もしそうなら、誰でもスレッドセーフな操作を知っていますか?

編集:私は、Java 1.6

EDITを使用しています:これは私が私の大きなアプリで何が起こっていたかテストするために作られた小さなプログラムです。私はこれを数回、より頻繁に走らなければならなかった。時間が同じであれば同じ乱数が出てくるはずだった。私のクイックプログラミングを許してください。

public class ThreadedRandom { 

/** 
* @param args 
*/ 
public static void main(String[] args) { 
    // TODO Auto-generated method stub 

    new ThreadedRandom().run(); 
} 

private RandomNumberGenerator _generator; 

public ThreadedRandom() 
{ 
    _generator = new RandomNumberGenerator(); 
} 

public void run() 
{ 
    Runnable r = new Runnable() { 
     @Override public void run() { 
      System.out.println(System.currentTimeMillis()+"\t"+_generator.gen()); 
     } 
    }; 

    Thread t1, t2; 

    t1 = new Thread(r); 
    t2 = new Thread(r); 

    t1.start(); 
    t2.start(); 
} 

private class RandomNumberGenerator { 

    Random random; 
    public RandomNumberGenerator() 
    { 
     random = new Random(); 
    } 

    public Long gen() { 
     return new Random().nextLong(); 
    } 
} 

}

+0

コードを投稿することができます –

+0

SecureRandomを参照してください - http://download.oracle.com/javase/7/docs/api/java/security/SecureRandom.html – jjnguy

+0

これは実際には起こりません。特にSystem.nanoTimeとvolatileのseedUniquifierを使用するため、頻繁に発生します。 – maaartinus

答えて

4

あなたはランダムの新しいインスタンスごとに作成されたくない場合があります。むしろ、グローバルなものを持っています。

+1

とnewオブジェクトを併用すると、これも期待されません。 –

+0

@org、それは毎回新しいランダムが期待されています。 Randomは現在のミリ秒でシードされているため、同じミリ秒内に2つのRandomsが作成されると、その数は同じになります。 – jjnguy

+1

誤っている。現在のバージョンのランダムは、 '++ seedUniquifier + System.nanoTime()'によってシードされます。これは非常に高い確率で一意のシードを生成するはずです。 – maaartinus

2

乱数は本当にランダムではなく、「疑似乱数」であり、「シード」値が必要です。同じシードが使用される場合、同じシーケンスの疑似ランダム値が生成されます。

Randomクラスの新しいインスタンスを作成するときは、自分で種子を指定するか、システムで選択することができます。 Javaでは、デフォルトの種子は、ミリ秒単位で、現在のシステム時刻で、次を参照してください。

http://download.oracle.com/javase/1.4.2/docs/api/java/util/Random.html#Random%28%29

を使用すると、同じミリ秒内のランダムなオブジェクトを作成した場合、彼らは同じ値のシーケンスを持つことになります。

通常、この種の問題を回避するために、すべての異なるスレッド間で単一のランダムオブジェクトを共有します。

+0

これは、サービス期間中のJavaバージョンでは当てはまりません。 [Java 5は、この問題が発生しないようにしました](http://download.oracle.com/javase/1.5.0/docs/api/java/util/Random.html#Random())、それは6年前にリリースされました: –

+0

真実ですが、古いJavaバージョンでは他のものより多くの時間を費やしています。 OPが使用しているバージョンを知りたいのは興味深いです。 –

+0

投稿を編集しました。 Java 1.6 –

1

Randomの基本的な実装にすぐには慣れていませんが、私が推測しなければならないのは、new Random()代理人をnew Random(System.currentTimeMillis())に呼び出すと想像します。これは、異なる時刻にインスタンス化されたRandomsのための合理的に異なるRandomシーケンスを与えます。

しかし、非同期呼び出しについて言及しているので、呼び出しが本質的に同時に実行されている可能性があります。これは、スレッドがライブラリを呼び出すときに同時に呼び出され、同じ時刻にnew Random()コールに遭遇し、Randomsが同じシードを取得するので、同じランダムシーケンスが生成されることを意味します。

+1

もう一度、Java 1.4に戻ったのですが、これは何年も前です。 –

0

ランダムはスレッドセーフではないと思っていましたが、それはあります。 2^48値ごとに同じ番号を生成するランダムを取得するだけです。

Java 1.4以前では、2つのRandomsが同じシードを取得できるバグがありました。私はあなたがJava 6を使用することをお勧めします。

ランダムは48ビットシードを使用することにも注意してください。つまり、2^48の値の後で繰り返され、2^48の一意のlong値しか生成されません。これが問題の場合は、はるかに高価なSecureRandomを使用しますが、すべての可能なlong値を生成します。

+2

間違っている、ランダムはスレッドセーフです。なぜあなたは彼らが揮発性とAtomicLongを使用していると思いますか?あなたは48ビットシードについて正しいです。 – maaartinus

+0

@maartinus、そうです。私はそれを修正しました。 –

+0

48ビットのシードは、実際には2^48の一意のlong値、または単純に2^48のユニークな*シーケンス*を生成するだけであることを意味しますか?明らかに、可能な最初の数の集合は2^48にしかならない。しかし、これは、最初の数字にできない数字がシーケンスの後のある時点で現れないことを意味するものではありません... –

1

SecureRandomは、セキュリティに関連するものに使用しているので、実際に使用する必要があります。

関連する問題