カウンターのための長い原始またはアトミックロング?
-
20-09-2019 - |
質問
タイプのカウンターが必要です long
次の要件/事実があります。
- カウンターを増やすことは、できるだけ時間がかかるはずです。
- カウンターは、1つのスレッドでのみ書き込まれます。
- カウンターから読むことは別のスレッドで行われます。
- カウンターは定期的に(1秒あたり数千回も)増加しますが、5秒ごとに1回しか読みません。
- 正確な精度は不可欠ではなく、カウンターのサイズの大まかなアイデアだけで十分です。
- カウンターは決してクリアされず、減少します。
これらの要件に基づいて、カウンターをどのように実装することを選択しますか?単純なものとして long
, 、 として volatile long
またはを使用します AtomicLong
?なんで?
現時点で私は持っています volatile long
しかし、別のアプローチがより良いかどうか疑問に思っていました。また、私はやることによって長い間漏れています ++counter
とは対照的に counter++
. 。課題が行われていないので、これは本当により効率的です(私は他の場所で信じるように導かれたので)?
解決
これらの要件セットを考えると、i 考える それa volatile
長いはずです。カウンターは非正しくないでしょうvolatile
長いですが、読者はその場合に古い情報を読んでいるかもしれません。
1つの問題は、aに読み書きして書いていることです long
それは いいえ 必要 原子になること, 、によって JVM仕様 宣言されていない場合 volatile
. 。つまり、ライティングスレッドが値の一部を更新している間に値を読み取っている場合、もう1つのものではない場合、読み取りスレッドがほとんど架空の値を得ることができます。
間の違い ++counter
と counter++
は おそらく JVMは、式の値がこれ以上使用されておらず、この場合は2つが同等であることを認識するため、無関係です。
他のヒント
Java 8では、スレッドの競合が高いAtomiclongよりもさらに優れているLongadderを使用します。
Longadder Javadoc:
このクラスは通常、複数のスレッドが統計を収集するなどの目的で使用される共通の合計を更新する場合、微細に粒度の同期制御ではなく、Atomiclongよりも好ましいです。更新の低い競合の下では、2つのクラスに同様の特性があります。しかし、高い競合の下では、このクラスの予想されるスループットは、より高いスペース消費を犠牲にして大幅に高くなっています。
あなたのプログラムの稼働時間要件は何ですか?不揮発性のINTとRACY-READSで間に合わせることができますか?
10^4増分 /秒は100 USECごとに1です。効率は問題ではありませんが、原子性はそうかもしれません。あなたはそれを2枚持っているかもしれません、そしてそれが読まれたとき、それらが等しくないならば、もう一度読んでください。
これ 論文 カウンターを実装する可能性のある方法について話します私はこの実装があなたのために働くべきだと思います
class LessNaiveVolatieIdGenerator {
private static volatile long id = 0;
public static long nextId() {
long nextId = (id = id + 1); // or nextId = id++;
return nextId;
}
}