java.utilのRandom.javaです。
乱数を得るメソッドはいくつもありますが、これらは最終的にnext(int)を呼びます。
なので、このnext(int)について比較します。
これがAndroid4.2のnext(int)です。
private static final long multiplier = 0x5deece66dL; protected synchronized int next(int bits) { seed = (seed * multiplier + 0xbL) & ((1L << 48) - 1); return (int) (seed >>> (48 - bits)); }
これがOpenJDK6のnext(int)です。
private final static long multiplier = 0x5DEECE66DL; private final static long addend = 0xBL; private final static long mask = (1L << 48) - 1; protected int next(int bits) { long oldseed, nextseed; AtomicLong seed = this.seed; do { oldseed = seed.get(); nextseed = (oldseed * multiplier + addend) & mask; } while (!seed.compareAndSet(oldseed, nextseed)); return (int)(nextseed >>> (48 - bits)); }
肝となる処理はどちらも同じですが、OpenJDKの方が一部の値を定数として保持している分綺麗だと思います。
違いはOpenJDKがAtmicLong#compareAndSet(long, long)でdo whileを回していることです。
AtmicLong#compareAndSet(long, long)はこちらの情報によると「この変数をこの新しい値に更新すること。ただし、このメソッドが最後に参照した後で他のスレッドによって値が変更された場合は、更新処理を失敗すること」とあります。
つまり、複数のスレッドから操作した場合にAndroidとOpenJDKで別の結果を得ることになるかもしれません。
0 件のコメント:
コメントを投稿