2012-09-14 12 views
10

नमूना कोड:क्या स्पष्ट लॉक स्वचालित रूप से स्मृति दृश्यता प्रदान करता है?

class Sample{ 
    private int v; 
    public void setV(){ 
     Lock a=new Lock(); 
     a.lock(); 
     try{ 
      v=1; 
     }finally{ 
      a.unlock(); 
     } 
    } 
    public int getV(){ 
     return v; 
    } 
} 

अगर मैं एक धागा लगातार getV आह्वान है और मैं सिर्फ एक और धागा में एक बार setV करते हैं, पढ़ने धागा लेखन के बाद नया मान सही देखने के लिए गारंटी है कि है? या मुझे "वी" अस्थिर या परमाणु संदर्भ बनाने की आवश्यकता है?

जवाब नहीं है, तो मैं इसे में बदलना चाहिए:

class Sample{ 
    private int v; 
    private Lock a=new Lock(); 
    public void setV(){ 
     a.lock(); 
     try{ 
      v=1; 
     }finally{ 
      a.unlock(); 
     } 
    } 
    public int getV(){ 
     a.lock(); 
     try{ 
      int r=v; 
     }finally{ 
      a.unlock(); 
     } 
     return r; 
    } 
} 
+0

क्या आपका मतलब है 'ReentrantLock'? –

+0

हां। लेकिन न केवल ReentrantLock बल्कि ग्रहण आरसीपी ढांचे से ISchedulingRule और ILock भी। –

उत्तर

7
documentation से

:

सभी लॉक कार्यान्वयन उसी स्मृति तुल्यकालन अर्थ विज्ञान के रूप में द्वारा प्रदान लागू करना चाहिए निर्मित की निगरानी ताला:

  • एक सफल ताला आपरेशन एक सफल monitorEnter कार्रवाई की तरह काम करता
  • एक सफल अनलॉक ऑपरेशन सफल मॉनिटर की तरह कार्य करता है एक्स्टिट एक्शन

यदि आप दोनों धागे (यानी। पठन और लेखन वाले लोग), रीडिंग थ्रेड नए मान को देखेंगे, क्योंकि monitorEnter कैश को फ़्लश करता है। अन्यथा, आपको रीडिंग थ्रेड में मेमोरी से पढ़ने के लिए परिवर्तनीय volatile घोषित करने की आवश्यकता है।

+0

क्या मैं थोड़ा और पूछ सकता हूं? क्या आप "कैश फ्लश" के बारे में कुछ और बता सकते हैं। क्या इसका कोई मतलब नहीं है कि कोई थ्रेड मॉनीटर में प्रवेश करता है, सभी प्रोसेसर अपने कैश को फ्लश करेंगे? या दर्ज मॉनिटर से संबंधित कैश डेटा फ्लश किया जाएगा? –

+0

@TempleWing मेरी समझ यह है कि जेवीएम मॉनीटर में प्रवेश करने से पहले कैश को फ्लश करता है, इसलिए हाँ, सभी विरोधी थ्रेड अपने कैश को स्मृति में फ्लश करेंगे, और फिर लॉक को एक-एक करके दर्ज करें। बेशक अगर कोई सीपीयू एक थ्रेड नहीं चलाता जो लॉक दर्ज करने का प्रयास करता है, तो CPUs कैश फ़्लश नहीं किया जाएगा। – dasblinkenlight

0

आप अस्थिर या एक AtomicInteger बनाना चाहिए। यह बीमा करेगा कि रीडिंग थ्रेड अंततः परिवर्तन को देखेगा, और अधिकांश उद्देश्यों के लिए "ठीक बाद" के लिए पर्याप्त बंद होगा। और तकनीकी रूप से आपको इस तरह के एक साधारण परमाणु अद्यतन के लिए लॉक की आवश्यकता नहीं है। AtomicInteger के एपीआई पर नजदीक देखो। सेट(), तुलना करें औरसेट(), आदि ... सभी मूल्यों को परमाणु रूप से धागे पढ़कर दृश्यमान सेट करने के लिए सेट करेंगे।

1

ब्रायन की विधि के अनुसार ...

आप एक ऐसा वैरिएबल अगले एक और धागा द्वारा पढ़ा जा सकता है लिख रहे हैं, या एक चर कि हो सकता है पिछले है द्वारा एक और धागा लिखा गया पढ़ने हैं, तो आपको सिंक्रनाइज़ेशन का उपयोग करें, और आगे, पाठक और लेखक को उसी मॉनीटर लॉक का उपयोग करके सिंक्रनाइज़ करना होगा।

तो यह दोनों सेटर और गेटर सिंक्रनाइज़ करने के लिए उपयुक्त होगा ......

या

उपयोग AtomicInteger.incrementAndGet() बजाय अगर आपlock-unlock ब्लॉक से बचना चाहते हैं (यानी सिंक्रनाइज़ ब्लॉक)

0

स्पष्ट ताले, synchronized, परमाणु संदर्भ और volatile, सभी स्मृति दृश्यता प्रदान करते हैं। लॉक और synchronized कोड अवरोध के लिए ऐसा करते हैं जो वे चारों ओर घूमते हैं और परमाणु संदर्भ और volatile विशेष चर घोषित करने के लिए करते हैं। हालांकि, सही ढंग से काम करने की दृश्यता के लिए, दोनों पढ़ने और लिखने के तरीकों को एक ही लॉकिंग ऑब्जेक्ट द्वारा संरक्षित किया जाना चाहिए।

यह आपके मामले में काम नहीं करेगा क्योंकि आपकी गेटर विधि लॉक द्वारा प्रक्षेपित नहीं की जाती है जो सेटर विधि की सुरक्षा करता है। यदि आप परिवर्तन करते हैं तो यह आवश्यकतानुसार काम करेगा। इसके अलावा वैरिएबल को volatile या AtomicInteger या AtomicReference<Integer> के रूप में घोषित करना भी काम करेगा।

1

अगर मैं एक धागा लगातार getV आह्वान किया है और मैं सिर्फ में एक बार setV एक और धागा करते हैं, पढ़ने धागा सही लेखन के बाद नया मान देखने के लिए गारंटी है कि है

नहीं, पढ़ने धागा सिर्फ अपनी एक प्रतिलिपि v के मूल्य का, और इस तरह नवीनतम मूल्य नहीं मिल (सीपीयू कोर जो पढ़ने धागा पर चल रहा है द्वारा स्वचालित रूप से कैश की गई) पढ़ सकते हैं।

या मुझे "वी" अस्थिर या परमाणु संदर्भ बनाने की आवश्यकता है?

हाँ, वे दोनों काम करते हैं।

, बनाना v अस्थिर बस कैशिंग v के मूल्य से सीपीयू कोर रोक यानी हर पढ़ चर v करने के लिए/ऑपरेशन लिखने मुख्य स्मृति है, जो धीमी (लगभग 100x बार एल 1 कैश से पढ़ने की तुलना में धीमी में प्रवेश करना होगा, के लिए interaction_latency देखना विवरण)

v = new AtomicInteger() का उपयोग कर काम करता है क्योंकि AtomicInteger दृश्यता प्रदान करने के लिए आंतरिक रूप से private volatile int value; का उपयोग करें।

और, यह भी अगर आप लॉक (चाहे एक Lock वस्तु या synchronized ब्लॉक या विधि का उपयोग करें) का उपयोग पढ़ने और लिखने धागा (के रूप में अपने दूसरे कोड खंड करता है) पर काम करता है, क्योंकि

( Second Edition of The Java ® Virtual Machine Specification खंड 8.9 के अनुसार)

... किसी भी ताला लॉक करना धारणात्मक एक थ्रेड काम स्मृति से सभी चर flushes, और किसी भी ताला खोलने सभी चर कि धागा सौंपा है के मुख्य स्मृति के लिए बाहर लिख ...

बलों .. यदि कोई थ्रेड किसी विशेष साझा चर का उपयोग करता है o लॉक करने के बाद nly लॉक के इसी अनलॉकिंग से पहले, तो थ्रेड लॉक ऑपरेशन के बाद मुख्य मेमोरी से उस चर के साझा मूल्य को पढ़ेगा, यदि आवश्यक हो, तो को मुख्य मेमोरी में कॉपी करेगा हाल ही में अनलॉक ऑपरेशन से पहले उस चर को असाइन किया गया मान।यह, ताले के लिए आपसी बहिष्कार नियमों के साथ संयोजन के रूप में, गारंटी नहीं है कि मूल्यों साझा चर के माध्यम से एक से दूसरे धागे से सही ढंग से प्रेषित कर रहे हैं पर्याप्त ...

पी.एस. AtomicXXXCAS (तुलना करें और स्वैप) संचालन भी प्रदान करता है जो उत्परिवर्ती पहुंच के लिए उपयोगी है।

पी.पी.एस. इस विषय पर जेवीएम विनिर्देश जावा 6 के बाद से नहीं बदला है, इसलिए उन्हें jvm specification for java 7, 8, and 9 में शामिल नहीं किया गया है।

पीपीपीएस this article के मुताबिक, प्रत्येक कोर के दृश्य से सीपीयू कैश हमेशा सुसंगत होते हैं। आपके प्रश्न की स्थिति 'मेमोरी ऑर्डरिंग बफर' के कारण होती है, जिसमें store & load निर्देश (जिसका उपयोग स्मृति से डेटा लिखने और पढ़ने के लिए किया जाता है) प्रदर्शन के लिए फिर से आदेश दिया जा सकता है। विस्तार से, बफर load निर्देश को पुराने store निर्देश से आगे निकलने की अनुमति देता है, जो वास्तव में समस्या का कारण बनता है। हालांकि, मेरी राय में, यह समझना अधिक कठिन है, इसलिए 'विभिन्न कोर (जैसे जेवीएम चश्मा किया गया) के लिए कैश एक बेहतर अवधारणा मॉडल हो सकता है।

+0

आगे चर्चा के लिए इस प्रश्न की जांच करें: https://stackoverflow.com/questions/1850270/memory-effects-of-synchronization-in-java –

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