2012-07-26 15 views
13

AtomicIntegerint से synchronized द्वारा संरक्षित तीव्रता के कम से कम क्रम में हो सकता है, मैं कभी भी परमाणु इंटेगर का उपयोग क्यों करना चाहूंगा?परमाणु इंटेगर सिंक्रनाइज़ किए जाने पर प्राथमिकता कब है?

उदाहरण के लिए, सभी मैं चाहता हूँ एक धागे-सुरक्षित तरीके से एक int मूल्य बढ़ाने के लिए है, तो क्यों नहीं always उपयोग:

synchronized(threadsafeint) { 
    threadsafeint++; 
} 

के बजाय बहुत धीमी AtomicInteger.incrementAndGet() का उपयोग कर?

उत्तर

17

चूंकि परमाणु इंटेगर कम से कम सिंक्रनाइज़ किए गए इंट की तुलना में धीमी गति का क्रम हो सकता है, तो मैं कभी भी परमाणु इंटेगर का उपयोग क्यों करना चाहूंगा?

परमाणु इंटेगर बहुत तेज है।

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 पता चलता है कुछ विवाद जोड़ा जा रहा है। यह दिखाता है कि जब आप केवल एक थ्रेड का उपयोग कर रहे हैं तो सीपीयू एक्सेस को अनुकूलित कर सकता है।

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

मुझे लगता है कि उनका मतलब है कि 'परमाणु इंटेगर' एक * असीमित * 'int' से धीमा है; वह इस बारे में बात कर रहा है कि आपको अपने सभी 'int' सदस्यों को औचित्य के बिना 'परमाणु इंटेगर' के साथ क्यों नहीं बदला जाना चाहिए। लेकिन यह तीव्रता का क्रम नहीं है, यह तीव्रता के क्रम की तुलना में कहीं अधिक है। अधिकांश भाग के लिए ये सभी छोटे मतभेद हैं जिनके बारे में हम बात कर रहे हैं। –

+0

मुझे याद है कि कहीं भी लॉकिंग तंत्र परमाणु सामान के लिए भी अलग है, लेकिन अभी उस संदर्भ को प्राप्त नहीं किया जा सका। मैं भी गलत हो सकता है। – kosa

2

यदि आप वास्तव में क्यों java.util.concurrent सामान बेहतर है पर अधिक जानकारी और क्या अंतर शास्त्रीय सिंक्रनाइज़ दृष्टिकोण की तुलना में है, this link पढ़ें (और पूरे ब्लॉग आम तौर पर) प्राप्त करना चाहते हैं

संबंधित मुद्दे