5

我目前正在做一个示例练习,我发现一个奇怪的观察结果,如果我用 volatile 替换 AutomicInteger 程序运行得更快。注意:我只做读取操作。

代码:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class Main {

AtomicInteger integer  = new AtomicInteger(100000000);
// volatile int integer= 100000000;

public static void main(String[] args) {
// We will store the threads so that we can check if they are done
List<Thread> threads = new ArrayList<Thread>();
 long start = System.currentTimeMillis();
 Main main = new Main();
// We will create 500 threads

for (int i = 0; i < 500; i++) {
  Runnable task = new MyRunnable(main.integer);
  Thread worker = new Thread(task);
  // We can set the name of the thread
  worker.setName(String.valueOf(i));
  // Start the thread, never call method run() direct
  worker.start();
  // Remember the thread for later usage
  threads.add(worker);
}
int running = 0;
do {
  running = 0;
  for (Thread thread : threads) {
    if (thread.isAlive()) {
      running++;
    }
  }
  System.out.println("We have " + running + " running threads. ");
} while (running > 0);

System.out.println("Total Time Required :" +(System.currentTimeMillis()- start));
}
} 

MyRunnable 类:

 import java.util.concurrent.atomic.AtomicInteger;

public class MyRunnable implements Runnable {
private final AtomicInteger countUntil;

MyRunnable(AtomicInteger countUntil) {
    this.countUntil = countUntil;
}

@Override
public void run() {
    long sum = 0;
    for (long i = 1; i < countUntil.intValue(); i++) {
        sum += i;
    }
    System.out.println(sum);
}
}

该程序在我的机器上使用 AutomicInteger 运行所需的时间。

所需总时间:102169

所需总时间:90375

该程序在我的机器上使用 volatile 运行所需的时间

所需总时间:66760

所需总时间:71773

这是否意味着 volatile 在读取操作方面也比 AutomicInteger 更快?

4

4 回答 4

6

AtomicInteger在阅读上下文中基本上是一个薄包装volatile int

private volatile int value;

public final int get() {
    return value;
}

public int intValue() {
    return get();
}

不要期望包装器比单独使用的包装器值更快。它只能与 JVM 使用的if 内联一样快。volatile int


并提示:如果你“只做读取操作”,这会更快:

static final int integer= 100000000;
于 2012-08-18T12:42:05.727 回答
1

这个问题取决于特定的 JVM、硬件和操作系统,所以唯一可能的答案是“也许”。

于 2012-08-18T12:41:16.600 回答
1

volatile int 比 AtomicInteger 快

原子访问和更新的记忆效应通常遵循 volatile 的规则,如Java™ 语言规范第 17.4 节所述。以下是 volatile int 与 Atomic 类型相比的缺点。

  • get 具有读取 volatile 变量的记忆效应。

  • set 具有写入(分配)易失性变量的记忆效应。

  • lazySet 具有写入(分配)易失性变量的记忆效应,除了它允许对后续(但不是先前)内存操作进行重新排序,这些操作本身不会对普通的非易失性写入施加重新排序约束。在其他使用上下文中,lazySet 可能在清空时应用,为了垃圾收集,一个永远不会再次访问的引用。

  • weakCompareAndSet 以原子方式读取和有条件地写入变量,但不会创建任何发生前的顺序,因此对于除weakCompareAndSet 的目标之外的任何变量的先前或后续读取和写入不提供任何保证。

  • compareAndSet 和所有其他读取和更新操作(例如 getAndIncrement)具有读取和写入 volatile 变量的记忆效应。

于 2013-11-19T05:33:32.847 回答
0

潜在的 volatile int 比 AtomicInteger 快,如果很少有应用程序会注意到这一点。尽管如此,AtomicInteger 提供了更广泛的潜在用途。

于 2012-08-18T12:42:33.200 回答