AtomicInteger何时优先于同步?
由于AtomicInteger
至少比synchronized
保护的int
慢一个数量级,为什么我要使用AtomicInteger?
例如,如果我想要的是以线程安全的方式增加int
值,为什么不总是使用:
synchronized(threadsafeint) { threadsafeint++; }
而不是使用慢得多的AtomicInteger.incrementAndGet() ?
由于AtomicInteger至少比同步保护的int慢一个数量级,为什么我要使用AtomicInteger?
AtomicInteger要快得多。
static final Object LOCK1 = new Object(); static final Object LOCK2 = new Object(); static int i1 = 0; static int i2 = 0; static final AtomicInteger ai1 = new AtomicInteger(); static final AtomicInteger ai2 = new AtomicInteger(); public static void main(String... args) throws IOException { for(int i=0;i<5;i++) { testSyncInt(); testAtomicInt(); } } private static void testSyncInt() { long start = System.nanoTime(); int runs = 10000000; for(int i=0;i< runs;i+=2) { synchronized (LOCK1) { i1++; } synchronized (LOCK2) { i2++; } } long time = System.nanoTime() - start; System.out.printf("sync + incr: Each increment took an average of %.1f ns%n", (double) time/runs); } private static void testAtomicInt() { long start = System.nanoTime(); int runs = 10000000; for(int i=0;i< runs;i+=2) { ai1.incrementAndGet(); ai2.incrementAndGet(); } long time = System.nanoTime() - start; System.out.printf("incrementAndGet: Each increment took an average of %.1f ns%n", (double) time/runs); }
版画
sync + incr: Each increment took an average of 32.4 ns incrementAndGet: Each increment took an average of 20.6 ns sync + incr: Each increment took an average of 31.4 ns incrementAndGet: Each increment took an average of 12.9 ns sync + incr: Each increment took an average of 29.6 ns incrementAndGet: Each increment took an average of 12.9 ns sync + incr: Each increment took an average of 35.1 ns incrementAndGet: Each increment took an average of 16.6 ns sync + incr: Each increment took an average of 29.9 ns incrementAndGet: Each increment took an average of 13.0 ns
添加一些争用为@assylias建议。 它表明,当您只使用一个线程时,CPU可以优化访问。
static final Object LOCK1 = new Object(); static final Object LOCK2 = new Object(); static int i1 = 0; static int i2 = 0; static final AtomicInteger ai1 = new AtomicInteger(); static final AtomicInteger ai2 = new AtomicInteger(); public static void main(String... args) throws ExecutionException, InterruptedException { for(int i=0;i<5;i++) { testSyncInt(); testAtomicInt(); } } private static void testSyncInt() throws ExecutionException, InterruptedException { long start = System.nanoTime(); final int runs = 1000000; ExecutorService es = Executors.newFixedThreadPool(2); List> futures = new ArrayList<>(); for(int t=0;t<8;t++) { futures.add(es.submit(new Callable() { public Void call() throws Exception { for (int i = 0; i < runs; i += 2) { synchronized (LOCK1) { i1++; } synchronized (LOCK2) { i2++; } } return null; } })); } for (Future future : futures) { future.get(); } es.shutdown(); long time = System.nanoTime() - start; System.out.printf("sync + incr: Each increment took an average of %.1f ns%n", (double) time/runs/2); } private static void testAtomicInt() throws ExecutionException, InterruptedException { long start = System.nanoTime(); final int runs = 1000000; ExecutorService es = Executors.newFixedThreadPool(2); List> futures = new ArrayList<>(); for(int t=0;t<8;t++) { futures.add(es.submit(new Callable () { public Void call() throws Exception { for (int i = 0; i < runs; i += 2) { ai1.incrementAndGet(); ai2.incrementAndGet(); } return null; } })); } for (Future future : futures) { future.get(); } es.shutdown(); long time = System.nanoTime() - start; System.out.printf("incrementAndGet: Each increment took an average of %.1f ns%n", (double) time/runs/2); }
版画
sync + incr: Each increment took an average of 478.6 ns incrementAndGet: Each increment took an average of 191.5 ns sync + incr: Each increment took an average of 437.5 ns incrementAndGet: Each increment took an average of 169.8 ns sync + incr: Each increment took an average of 408.1 ns incrementAndGet: Each increment took an average of 180.8 ns sync + incr: Each increment took an average of 511.5 ns incrementAndGet: Each increment took an average of 313.4 ns sync + incr: Each increment took an average of 441.6 ns incrementAndGet: Each increment took an average of 219.7 ns
如果你真的想获得更多关于为什么java.util.concurrent
东西更好以及与经典同步方法相比有什么不同的细节,请阅读此链接 (以及整个博客)