2012-07-01 52 views
8

मुझे हाल ही में अस्थिर कीवर्ड के इस अजीब व्यवहार का अनुभव हुआ है। जहाँ तक मुझे पता है,क्यों अस्थिर अजीब व्यवहार कर रहा है

  1. अस्थिर कीवर्ड परिवर्तन अन्य धागा पर एक धागा द्वारा चर के डेटा पर किया प्रतिबिंबित करने के लिए चर के लिए पर लागू किया जाता है।

  2. अस्थिर कीवर्ड धागे पर डेटा के कैशिंग को रोकता है।

मैं एक छोटे से परीक्षण ........

  1. मैं एक पूर्णांक चर गिनती नामित इस्तेमाल किया था, और उस पर अस्थिर कीवर्ड का इस्तेमाल किया।

  2. फिर 10000 के लिए चर मूल्य बढ़ाने के लिए 2 अलग धागे बनाया है, तो अंत परिणामी 20000.

  3. होना चाहिए लेकिन ऐसा नहीं thats हमेशा की तरह, मैं अस्थिर कीवर्ड के साथ 20000 लगातार नहीं मिल रहा हो रही है, लेकिन 18,534, 15000, आदि .... और कभी कभी 20000.

  4. लेकिन जब मैं कीवर्ड सिंक्रनाइज़ करते थे, तब भी वह अच्छे काम किया, क्यों .... ??

क्या कोई मुझे अस्थिर कीवर्ड के इस व्यवहार को समझा सकता है।

मैं अपने कोड को अस्थिर कीवर्ड के साथ-साथ सिंक्रनाइज़ किए गए कीवर्ड के साथ पोस्ट कर रहा हूं।

निम्नलिखित कोड नीचे चर गिनती पर अस्थिर कीवर्ड के साथ असंगत व्यवहार करती है

public class SynVsVol implements Runnable{ 

    volatile int count = 0; 

    public void go(){ 

     for (int i=0 ; i<10000 ; i++){ 
      count = count + 1; 
     } 
    } 

    @Override 
    public void run() { 
     go(); 
    } 

    public static void main(String[] args){ 

     SynVsVol s = new SynVsVol(); 
     Thread t1 = new Thread(s); 
     Thread t2 = new Thread(s); 
     t1.start(); 
     t2.start(); 

     try { 
      t1.join(); 
      t2.join(); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     System.out.println("Total Count Value: "+s.count); 
    } 
} 

निम्नलिखित कोड विधि चलते-फिरते सिंक्रनाइज़ कीवर्ड के साथ पूरी तरह बर्ताव करता है()।

public class SynVsVol implements Runnable{ 

    int count = 0; 

    public synchronized void go(){ 
     for (int i=0 ; i<10000 ; i++){ 
      count = count + 1; 
     } 
    } 

    @Override 
    public void run() { 
     go(); 
    } 

    public static void main(String[] args){ 

     SynVsVol s = new SynVsVol(); 
     Thread t1 = new Thread(s); 
     Thread t2 = new Thread(s); 
     t1.start(); 
     t2.start(); 

     try { 
      t1.join(); 
      t2.join(); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     System.out.println("Total Count Value: "+s.count); 
    } 
} 
+0

हमम दिलचस्प! +1। – GETah

+0

संभावित डुप्लिकेट [फ़ील्ड रीड और अस्थिरता के सिंक्रनाइज़ेशन के बीच अंतर] (http://stackoverflow.com/questions/3103204/difference-between-synchronization-of-field-reads-and-volatile) – Mat

+0

कल्पना करें कि एक थ्रेड स्विच हो गया है 'गिनती = गिनती + 1' निर्देश के दौरान - खासकर जब यह 'गिनती' उठाता है और इससे पहले कि यह 'गिनती + 1' स्टोर करता है। आपको यह देखने की ज़रूरत है कि यह कुछ हज़ार बार हो रहा है और आप कर चुके हैं। इसे ठीक करने के लिए 'AtomicInteger' का उपयोग करें। – OldCurmudgeon

उत्तर

7

volatile कीवर्ड एक सिंक्रनाइज़ेशन आदिम नहीं है। यह केवल धागे पर मूल्य की कैशिंग को रोकता है, लेकिन यह दो धागे को एक ही मूल्य को संशोधित करने और इसे समवर्ती रूप से लिखने से नहीं रोकता है।

मान लें कि दो धागे उस बिंदु पर आते हैं जब उन्हें काउंटर को बढ़ाने की आवश्यकता होती है, जो अब 5 पर सेट हो जाती है। दोनों धागे 5 देखते हैं, इसमें से 6 बनाते हैं, और इसे काउंटर में वापस लिखते हैं। यदि काउंटर volatile नहीं था, तो दोनों धागे मान सकते थे कि वे जानते हैं कि मान 6 है, और अगले पढ़ने को छोड़ दें। हालांकि, यह अस्थिर है, इसलिए वे दोनों 6 वापस पढ़ेंगे, और वृद्धि जारी रखें। चूंकि थ्रेड लॉक-चरण में नहीं जा रहे हैं, इसलिए आप आउटपुट में 10000 से अलग मान देख सकते हैं, लेकिन 20000 के लिए आपको कोई मौका नहीं है।

+0

अस्थिर कीवर्ड एक सिंक्रनाइज़ेशन आदिम नहीं है।लेकिन यह आमतौर पर सिंक्रनाइज़ेशन उद्देश्य के लिए प्रयोग किया जाता है। – nnhthuan

+1

मुझे नहीं लगता कि यह सच है। अस्थिर कार्य करता है जैसे कि यह एक सिंक्रनाइज़ ब्लॉक में संलग्न है, स्वयं पर सिंक्रनाइज़ किया गया है। – GETah

+0

@codesparkle ने – GETah

4

तथ्य एक चर volatile मतलब यह नहीं है कि हर आपरेशन इसमें शामिल है परमाणु है कि। उदाहरण के लिए, SynVsVol.Go में इस लाइन:

count = count + 1; 

पहले count पढ़ा, तो वृद्धि की जाती है, और परिणाम फिर वापस लिखा जाएगा। यदि कुछ अन्य धागे एक ही समय में इसे निष्पादित करेंगे, तो परिणाम कमांड के अंतःक्रिया पर निर्भर करते हैं।

अब, जब आप syncronized, SynVsVol.Go परमाणु रूप से निष्पादित करते हैं। अर्थात्, वृद्धि पूरी तरह से एक थ्रेड द्वारा की जाती है, और दूसरा इसे पूरा होने तक count संशोधित नहीं कर सकता है।

आखिरकार, सदस्य चर के कैशिंग को सिंक्रनाइज़ किए गए ब्लॉक में केवल संशोधित किया जाना बहुत आसान है। मॉनिटर अधिग्रहित होने पर कंपाइलर अपना मूल्य पढ़ सकता है, इसे रजिस्टर में कैश कर सकता है, उस रजिस्टर पर किए गए सभी बदलाव हो सकते हैं, और अंततः मॉनीटर जारी होने पर इसे मुख्य मेमोरी पर वापस फ्लश कर सकते हैं।यह तब भी होता है जब आप सिंक्रनाइज़ किए गए ब्लॉक में wait पर कॉल करते हैं, और जब कुछ अन्य थ्रेड notify आप हैं: कैश्ड सदस्य चर सिंक्रनाइज़ किए जाएंगे, और आपका प्रोग्राम सुसंगत रहेगा। That's guaranteed भले ही सदस्य चर अस्थिर रूप में घोषित नहीं किया गया है:

तुल्यकालन कि स्मृति से पहले एक धागे से लिखते हैं या एक तुल्यकालन ब्लॉक के दौरान अन्य सूत्र जो एक ही मॉनीटर पर सिंक्रनाइज़ करने के लिए एक उम्मीद के मुताबिक तरीके से में दृश्यमान हो जाने सुनिश्चित करता है ।

3

आपका कोड टूटा हुआ है क्योंकि यह volatile पर परमाणु के रूप में पढ़ने और वृद्धि के संचालन का इलाज करता है, जो यह नहीं है। कोड में डेटा रेस नहीं है, लेकिन इसमें रेस कंडीशनint पर है।

12

count = count + 1 परमाणु नहीं है।

  1. चर
  2. वृद्धि मान
  3. चर

इन तीन चरणों के लिए वापस नया मान लिखने के वर्तमान मूल्य पढ़ गूंथा जा रहा है, जिसका परिणाम: यह तीन चरण हैं विभिन्न निष्पादन पथ, जिसके परिणामस्वरूप गलत मान होता है। यदि आप सिंक्रनाइज़ किए गए कीवर्ड से बचना चाहते हैं तो इसके बजाय AtomicInteger.incrementAndGet() का उपयोग करें।

तो हालांकि volatile कीवर्ड आपके द्वारा वर्णित अनुसार बहुत अधिक कार्य करता है, जो केवल प्रत्येक पृथक ऑपरेशन पर लागू होता है, न कि सभी तीन संचालन सामूहिक रूप से।

+0

मुझे विश्वास है कि यह सही जवाब है। +1 – GETah

+0

यूप - यह किसी भी के रूप में अच्छा जवाब है :) –

+0

Yup। जैसा कि मैं इसे समझता हूं, 'अस्थिर' का अर्थ परमाणु पढ़ता है और लिखता है, लेकिन उदा। तुलना और निर्धारित किया है। –