2012-07-26 13 views
13

Ponieważ AtomicInteger może być co najmniej o rząd wielkości wolniejszy niż int chroniony przez synchronized, dlaczego miałbym kiedykolwiek chcieć używać AtomicInteger?Kiedy AtomicInteger jest bardziej preferowany niż zsynchronizowany?

Na przykład, jeśli wszystko czego chcę to, aby zwiększyć wartość w sposób bezpieczny wątku int, dlaczego nie always użytku:

synchronized(threadsafeint) { 
    threadsafeint++; 
} 

zamiast używania znacznie wolniejsze AtomicInteger.incrementAndGet()?

Odpowiedz

17

Od AtomicInteger może być co najmniej o rząd wielkości mniejszą niż int chronionym przez zsynchronizowany, dlaczego miałbym kiedykolwiek chcesz użyć AtomicInteger?

AtomicInteger jest znacznie szybszy.

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); 
} 

drukuje

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 

dodając niektóre twierdzenia jako @assylias sugeruje. Pokazuje, że jeśli używasz tylko jednego wątku, procesor może zoptymalizować dostęp.

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); 
} 

drukuje

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

Jestem teraz naprawdę zdezorientowany. To nie jest to, co zrozumiałam z odpowiedzi @ Greya tutaj: http://stackoverflow.com/a/11125474/722603 Czego mi brakuje? – ef2011

+0

Myślę, że on oznacza, że ​​'AtomicInteger' jest wolniejszy niż * niezsynchronizowany *' int'; on mówi o tym, dlaczego nie powinieneś zastępować wszystkich swoich "int" członkami 'AtomicInteger' bez uzasadnienia. Ale nie jest to rząd wielkości wolniejszy, bardziej niż o rząd wielkości szybszy. W przeważającej części są to wszystkie małe różnice, o których mówimy. –

+0

Pamiętam, że czytałem gdzieś, że mechanizm blokujący również różni się od rzeczy Atomowych, ale nie mógł teraz uzyskać tego odniesienia. Też mogę się mylić. – kosa

2

jeśli naprawdę chcesz uzyskać (zwykle i cały blog) Więcej informacji na temat dlaczego java.util.concurrent rzeczy jest lepsze i jaka jest różnica w porównaniu do klasycznego zsynchronizowanego podejścia, przeczytaj this link

Powiązane problemy