AtomicInteger
和之间有任何性能差异Integer
吗?
5 回答
这两种类型的选择不应取决于性能。的主要选择AtomicInteger
是如果您想通过对整数的操作来实现线程安全。
然而,性能差异可能很大程度上取决于所选的操作系统,因为原子操作的详细实现取决于操作系统。
AtomicInteger
允许使用特殊硬件指令以无锁方式执行一些(不是全部!)操作。这如何影响性能有点复杂:
- 首先,它是一个微优化,只有当这个特定操作在您的应用程序的关键路径上时才有意义。
- 特殊的硬件指令可能在非主流平台上不可用,在这种情况下
AtomicInteger
可能会使用同步来实现。 - 当没有争用(例如,单线程应用程序)时,JVM 通常可以优化掉锁定开销。在这种情况下,可能没有区别。
- 如果存在低到中度的锁争用(即多个线程,但它们主要做其他事情而不只是访问该整数),则无锁算法的性能优于同步。
- 如果存在非常严重的锁争用(即大量线程花费大量时间试图访问该整数),同步可能会执行得更好,因为无锁算法基于在由于冲突而失败时不断重试操作。
好吧,如果你在多线程环境中使用它,例如计数器,那么你必须synchronize
访问 Integer
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/
编辑使用 incrementAndGet
今天看到这篇文章,但想分享我的结果(请不要对代码发表评论,因为我必须手动输入以下类,因为我运行这个的系统没有连接到互联网 :)
下面代码的输出如下:
原子结果: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)));
}
增量原子运行:
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.");
}
}
除了非常小的同步开销之外,没有。