と の間にパフォーマンスの違いはAtomicInteger
ありInteger
ますか?
5 に答える
これら 2 つのタイプの選択は、パフォーマンスに依存するべきではありません。の主な選択AtomicInteger
は、整数の操作でスレッド セーフを実現する場合です。
ただし、パフォーマンスの違いは、選択したオペレーティング システムに大きく依存する場合があります。これは、アトミック操作の詳細な実装がオペレーティング システムに依存するためです。
AtomicInteger
特別なハードウェア命令を使用して、ロックなしの方法で同期を実行する必要がある一部の(すべてではない!)操作を許可します。これがパフォーマンスに与える影響はやや複雑です。
- まず、これは、この特定の操作がアプリケーションのクリティカルパス上にある場合にのみ問題となるマイクロ最適化です。
- 特別なハードウェア命令は、非主流のプラットフォームでは利用できない場合があります。その場合、
AtomicInteger
おそらく同期を使用して実装されます。 - JVMは、競合がない場合(たとえば、シングルスレッドアプリケーション)、ロックのオーバーヘッドを最適化できることがよくあります。その場合、おそらく違いはありません。
- 低から中程度のロック競合がある場合(つまり、複数のスレッドがありますが、ほとんどの場合、その整数にアクセスする以外のことを行います)、ロックフリーアルゴリズムは同期よりも優れたパフォーマンスを発揮します。
- ロックの競合が非常に激しい場合(つまり、その整数へのアクセスに多くの時間を費やすスレッドが多い場合)、ロックフリーアルゴリズムは、衝突が原因で失敗したときに操作を常に再試行することに基づいているため、同期のパフォーマンスが向上する可能性があります。
マルチスレッド環境で、たとえばカウンターとして使用する場合はsynchronize
、整数にアクセスする必要があります
public final class Counter {
private long value = 0;
public synchronized long getValue() {
return value;
}
public synchronized long increment() {
return ++value;
}
}
同期なしで AtomicInteger を使用すると、パフォーマンスが大幅に向上しますが、
public class NonblockingCounter {
private AtomicInteger value;
public int getValue() {
return value.get();
}
public int increment() {
return value.incrementAndGet();
}
}
推奨読書http://cephas.net/blog/2006/09/06/atomicinteger/
EDITはincrementAndGetを使用します
今日この投稿に出くわしましたが、私の結果を共有したいと思いました (これを実行したシステムがインターネットに接続されていなかったため、次のクラスを手動で入力する必要があったため、コードに関するコメントはありません:)
以下のコードからの出力の結論は次のとおりです。
ATOMIC 結果: Elapsed = 25257 ms、ExpectedValue = 50000、FinalValue = 50000、true PrImItIvE 結果: Elapsed = 25257 ms、ExpectedValue = 50000、FinalValue = 48991、false
私の特定のアプリで使用するために、監視クラスのステータス番号にアトミック値を使用することにしました。他の誰かがいくつかのハードな結果を見たいと思った場合に備えて、私はこの情報を投稿することにしました.
すてきな一日を!
クラス:
プリミティブ long とアトミック long およびアクセサーのインクリメント メソッド、IncrementAtomicRunnable と IncrementPrimitiveRunnable を使用してメイン クラスを作成しました。
ロングオーバーヘッド:
public class LongOverhead{
AtomicLong atomicLong;
long primitiveLong;
public LongOverhead(){
atomicLong = new AtomicLong(0l);
primitiveLong = 0l;
}
public void incrAtomicLong(){
atomicLong.getAndAdd(1l);
}
public long getAtomicLong(){
return atomicLong.get();
}
public void incrPrimitiveLong(){
primitiveLong++;
}
public long getPrimitiveLong(){
return primitiveLong;
}
public static void main(String [] args){
String template = "%s Results: Elapsed = %d ms, ExpectedValue = %d, FinalValue = %d, %b";
int loopTotal = 1000;
int waitMilliseconds = 25;
int totalThreads = 50;
int expectedValue = loopTotal * totalThreads;
int whileSleep = 250;
LongOverhead atomic = new LongOverhead();
LongOverhead primitive = new LongOverhead();
List<Thread> atomicThreads = new ArrayList<>();
List<Thread> primitiveThreads = new ArrayList<>();
for(int x=0;x<totalThreads;x++){
Thread a = new Thread(new IncrementalAtomicRunnable(atomic, loopTotal, waitMilliseconds), "AtomicIncr" + x);
atomicThreads.add(a);
Thread p = new Thread(new IncrementalPrimitiveRunnable(primitive, loopTotal, waitMilliseconds), "PrimitiveIncr" + x);
primitiveThreads.add(p);
}
boolean cont = true;
long atomicStart = System.currentTimeMillis();
for(Thread t: atomicThreads){
t.start();
}
while(cont){
try{
Thread.sleep(whileSleep);
}catch(InterruptedException e){
e.printStackTrace();
}
boolean foundAlive = false;
for(Thread t: atomicThreads){
foundAlive = (State.TERMINATED != t.getState());
if(foundAlive){
break;
}
}
cont = foundAlive;
}
long atomicFinish = System.currentTimeMillis();
long atomicElapsed = atomicFinish - atomicStart;
long atomicFinal = atomic.getAtomicLong();
cont = true;
long primitiveStart = System.currentTimeMillis();
for(Thread t: primitiveThreads){
t.start();
}
while(cont){
try{
Thread.sleep(whileSleep);
}catch(InterruptedException e){
e.printStackTrace();
}
boolean foundAlive = false;
for(Thread t: primitiveThreads){
foundAlive = (State.TERMINATED != t.getState());
if(foundAlive){
break;
}
}
cont = foundAlive;
long primitiveFinish = System.currentTimeMillis();
long primitiveElapsed = primitiveFinish - primitiveStart;
long primitiveFinal = primitive.getPrimitiveLong();
System.out.println(String.format(template, "ATOMIC", atomicElapsed, expectedValue, atomicFinal, (expectedValue==atomicFinal)));
System.out.println(String.format(template, "PrImItIvE", primitiveElapsed, expectedValue, primitiveFinal, (expectedValue==primitiveFinal)));
}
IncrementAtomicRunnable:
public class IncrementAtomicRunnable implements Runnable{
protected LongOverhead oh;
protected int loopTotal;
protected int waitMilliseconds;
protected String currentThreadName;
public IncrementAtomicRunnable(LongOverhead oh, int loopTotal, int waitMilliseconds){
this.oh = oh;
this.loopTotal = loopTotal;
this.waitMilliseconds = waitMilliseconds;
}
@Override
public void run(){
currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " for ATOMIC is starting.....");
for(int x=0;x<loopTotal;x++){
oh.incrAtomicLong();
try{
Thread.sleep(waitMilliseconds);
}catch(InterruptedException e){
System.out.println("InterruptedThread[" + currentThreadName + "], eating exception @@@@@");
}
}
System.out.println("....." + currentThreadName + " for ATOMIC is finished.");
}
}
そして最後に IncrementPrimitiveRunnable:
public class IncrementPrimitiveRunnable extends IncrementAtomicRunnable{
public IncrmentPrimitiveRunnable(LongOverhead oh, int loopTotal, int waitMilliseconds){
super(oh, loopTotal, waitMilliseconds);
}
@Override
public void run(){
super.currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " for PRIMITIVE is starting.....");
for(int x=0;x<loopTotal;x++){
oh.incrPrimitiveLong();
try{
Thread.sleep(waitMilliseconds);
}catch(InterruptedException e){
System.out.println("InterruptedThread[" + currentThreadName + "], eating exception @@@@@");
}
}
System.out.println("....." + currentThreadName + " for PRIMITIVE is finished.");
}
}
非常に小さな同期オーバーヘッドを除けば、いいえ。