1
class ABC{
private static Random random = new Random();
private static AtomicLong uniqueLongId = new AtomicLong(System.currentTimeMillis());

public static long getUniqueLongId(){

            long id = uniqueLongId.incrementAndGet();
            long uniqueID = Math.abs(random.nextLong()) + id;
            return uniqueID;

            //the above code we can write in one line
    //return Math.abs(random.nextLong())+uniqueLongId.incrementAndGet();

}
}

上記のメソッドgetUniqueLongId()は、マルチスレッド環境で一意のIDを提供しますか?ここでの私の懸念は次のとおりです。uniqueLongIdがアトミックであり、incrementAndGet()の呼び出しがスレッドセーフな呼び出しであると想定していますが、コードの他の部分は同期されていません。これは、メソッドgetUniqueLongId()自体がスレッドセーフではないことを意味するのではないでしょうか。したがって、必ずしも一意のIDを返さない可能性がありますか?

説明してください..

4

2 に答える 2

3

Java 7 ドキュメントには次のように書かれています。

のインスタンスjava.util.Randomはスレッドセーフです。ただし、複数のスレッドで同じインスタンスを同時に使用すると、java.util.Random競合が発生し、パフォーマンスが低下する可能性があります。代わりThreadLocalRandomにマルチスレッド設計で使用することを検討してください。

したがって、コードは Java 7 でスレッド セーフです。すべての操作は、スレッド セーフなメソッドの呼び出しか、ローカル変数のみの操作です。また、原子性は必要ありません。つまり、次のシーケンス番号を次の乱数とペアにする必要はありません。

(あなたのコメントによると)APIドキュメントの古いバージョンにはそのような保証がないため、実装は理論的にはスレッドセーフではない可能性があります。ただし、src.zipSun JDK 1.4.2.19 (私が持っている最も古いバージョン) を見ると、そのコードは既にアトミック変数を使用しているため、実際にはスレッドセーフな動作を提供しています。

とはいえ、あなたのコードには他にも多くの問題があります。上記のように、パフォーマンスが悪い可能性があります。assylias がすでにコメントに書いているように、このアプローチでは、単純な方法よりも一意の番号が得られませんRandom。さらに、Math.abs(Long.MIN_VALUE)は依然として負であり、正の乱数と id によってオーバーフローとラップアラウンドが発生する可能性があります。したがって、正の数が必要な場合は、さらに注意を払う必要があります。決勝は途中uniqueID &= 0x7fffffffffffffffLよりも適しているかもしれません。Math.abs

于 2013-02-06T14:04:02.580 に答える
1

それは確かにスレッドセーフです。MvGの答えはその理由を説明しています。

@assylias で指摘されているように、シングル スレッド環境では一意の ID さえ生成されない場合があります。

ObjectIdMongoDBの生成メカニズムを勉強する価値はあります。

一意性を確保するために導入された 4 つのパラメーターがあります。

a 4-byte timestamp,
a 3-byte machine identifier,
a 2-byte process id, and
a 3-byte counter.

そうは言っても、UUIDこの目的のためにすぐに使用できるJDKのクラスがあります。

注意点は、JDK 7 まではスレッドセーフではなかったということです。

于 2013-02-06T14:04:48.797 に答える