2012-07-26 4 views
13

AtomicIntegerintsynchronized에 의해 보호되는 것보다 적어도 1 배 이상 느릴 수 있으므로 왜 AtomicInteger를 사용하고 싶습니까? 내가 원하는 모든 스레드 안전한 방식으로 int 값을 증가하는 경우 예를 들어AtomicInteger는 동기화가 언제 더 좋은가?

, 왜 안 always 사용 :

synchronized(threadsafeint) { 
    threadsafeint++; 
} 

대신 AtomicInteger.incrementAndGet() 훨씬 느린 사용하고 계십니까?

답변

17

AtomicInteger는 적어도 synchronized의 보호를받는 int보다 느릴 수 있으므로 AtomicInteger를 사용하고 싶습니다.

AtomicInteger가 훨씬 빠릅니다. @assylias에서 알 수 있듯이 일부 경합을 추가

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 

. 그것은 단지 하나의 쓰레드만을 사용하고있을 때 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<Future<Void>> futures = new ArrayList<>(); 
    for(int t=0;t<8;t++) { 
     futures.add(es.submit(new Callable<Void>() { 
      public Void call() throws Exception { 
       for (int i = 0; i < runs; i += 2) { 
        synchronized (LOCK1) { 
         i1++; 
        } 
        synchronized (LOCK2) { 
         i2++; 
        } 
       } 
       return null; 
      } 
     })); 
    } 
    for (Future<Void> 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<Future<Void>> futures = new ArrayList<>(); 
    for(int t=0;t<8;t++) { 
     futures.add(es.submit(new Callable<Void>() { 
      public Void call() throws Exception { 
       for (int i = 0; i < runs; i += 2) { 
        ai1.incrementAndGet(); 
        ai2.incrementAndGet(); 
       } 
       return null; 
      } 
     })); 
    } 
    for (Future<Void> 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 
+0

저는 이제 정말로 혼란 스럽습니다. 그게 내가 @ 그레이의 대답에서 이해가 아니야 : http://stackoverflow.com/a/11125474/722603 내가 무엇을 놓치고 있습니까? – ef2011

+0

나는 그가'AtomicInteger'가 unsynchronized *'int'보다 느리다는 것을 의미한다고 생각합니다; 그는 왜 당신이'int '멤버를'AtomicInteger'로 대체하지 말아야하는지에 대해 말하고 있습니다. 그러나 크기의 순서가 그보다 더 빠르지 않습니다. 대부분 이것들은 모두 우리가 이야기하고있는 작은 차이입니다. –

+0

나는 어딘가에서 원자 구조에 대해 잠금 메커니즘이 다르다는 것을 기억하지만 지금은 그 참조를 얻을 수 없었다. 나는 틀릴 수도 있습니다. – kosa

2

당신이 정말로 (일반적으로 전체 블로그) 더 java.util.concurrent 물건이 더 좋은 이유에 대한 자세한 내용과 어떤 차이가 고전 동기화 방식과 비교, this link 읽기를 얻으려면