2010-06-03 16 views
14

कहें कि मेरे पास दो धागे और एक वस्तु है।मैं जावा में अस्थिर कीवर्ड का सही तरीके से उपयोग कैसे कर सकता हूं?

public void use() { 
    myObject.use(); 
} 

चर myObject अस्थिर रूप में घोषित किए जाने की है:

public void assign(MyObject o) { 
    myObject = o; 
} 

एक और धागा वस्तु का उपयोग करता है: एक धागा वस्तु प्रदान करती है? मैं समझने की कोशिश कर रहा हूं कि अस्थिरता का उपयोग कब करें और कब नहीं, और यह मुझे परेशान कर रहा है। क्या यह संभव है कि दूसरा थ्रेड किसी पुराने ऑब्जेक्ट को स्थानीय मेमोरी कैश में संदर्भित रखता है? यदि नहीं, तो क्यों नहीं?

बहुत बहुत धन्यवाद।

+1

जावा का कौन सा संस्करण आप उपयोग कर रहे हैं? – Alerty

+0

मैं मोबाइल डिवाइस पर विकास कर रहा हूं। यह मूल रूप से जावा 1.4.x – Tiyoal

उत्तर

6

पीछे जटिल तकनीकी जानकारी छोड़कर, आप चर के लिए volatile कम या अधिक एक synchronized आपरिवर्तक के रूप में देख सकते हैं।

public synchronized void doSomething() {} 

आप चर के लिए उपयोग "सिंक्रनाइज़" करना चाहते हैं, तो आप फिर ': आप तरीकों या ब्लॉक करने के लिए उपयोग सिंक्रनाइज़ करना चाहते हैं, तो आप आमतौर पर इस प्रकार synchronized संशोधक का उपयोग करना चाहते हैं d volatile संशोधक का उपयोग करना चाहते:

private volatile SomeObject variable; 

दृश्यों वे अलग अलग बातें करते हैं के पीछे, लेकिन प्रभाव एक ही है: परिवर्तन तुरंत अगले एक्सेस थ्रेड के लिए दिखाई दे रहे हैं।

आपके विशिष्ट मामले में, मुझे नहीं लगता कि volatile संशोधक का कोई मूल्य है। volatile किसी भी तरह से गारंटी नहीं देता है कि ऑब्जेक्ट का उपयोग करने वाले थ्रेड ऑब्जेक्ट का उपयोग करके थ्रेड चलाएगा। यह दूसरे तरीके से अच्छा हो सकता है। आप शायद use() विधि में पहले एक नलचेक करना चाहते हैं।

अद्यतन: भी this article देखें:

चर में कार्य करता है के रूप में यद्यपि यह एक तुल्यकालन ब्लॉक में संलग्न है के लिए प्रवेश, खुद पर सिंक्रनाइज़। हम दूसरे बिंदु पर "जैसा कार्य करते हैं" कहते हैं, क्योंकि कम से कम प्रोग्रामर (और शायद अधिकांश जेवीएम कार्यान्वयन में) में कोई वास्तविक लॉक ऑब्जेक्ट शामिल नहीं है।

+7

है यह पूरी तरह गलत है। अस्थिरता पूरी तरह से स्मृति प्रभाव और एक चर के दृश्यता के बारे में है, समवर्ती पहुंच नहीं। – Kevin

+0

मैं उलझन में हूँ। मैं पढ़ रहा हूं और मैंने पढ़ा है कि अस्थिर आमतौर पर धागे के बीच ध्वज साझा करने के लिए प्रयोग किया जाता है: एक धागे धागे को झूठ में सेट करते हैं, और अन्य नोटिस जो झूठे पर सेट किए गए हैं। यदि बूलियन को अस्थिर घोषित नहीं किया जाता है, तो दूसरा धागा हमेशा ध्यान देगा कि यह गलत पर सेट किया गया है, क्योंकि मान स्थानीय थ्रेड कैश में संग्रहीत किया जा सकता है। क्या यह सच नहीं है या क्या मैंने उस कथन को गलत समझा? – Tiyoal

+3

@ केविन: हाँ, यह तकनीकी विवरण है। मैं ** प्रभाव ** के बारे में बात कर रहा था ताकि स्टार्टर्स के लिए यह अधिक समझ में आता है। परिवर्तनीय में परिवर्तन अगली एक्सेसिंग थ्रेड के लिए तुरंत दिखाई देता है। – BalusC

11

मैं समझता हूँ कि जब अस्थिर और जब आप ज्यादातर इसे का उपयोग करने से बचना चाहिए नहीं

उपयोग करने के लिए कोशिश कर रहा हूँ। इसके बजाय AtomicReference का उपयोग करें (या उचित atomic कक्षा जहां उचित हो)। स्मृति प्रभाव समान हैं और इरादा अधिक स्पष्ट है।

मैं बेहतर समझने के लिए उत्कृष्ट Java Concurrency in Practice पढ़ने का सुझाव देता हूं।

+2

सलाह के लिए धन्यवाद। मैं सहमत हूं कि मुझे इन 'निम्न स्तर की सामग्री' का उपयोग नहीं करना है। हालांकि, मुझे यह समझने का आग्रह होता है कि यह हुड के नीचे कैसे काम करता है। पुस्तक इसके लिए एक बहुत अच्छा सुझाव है। धन्यवाद। – Tiyoal

+0

@Tiyoal पूर्ण नट किरकिरा के लिए, जेएलएस की धारा 17.4 देखें जो मेमोरी मॉडल पर चर्चा करता है: http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.4 – Kevin

+0

दूसरा समवर्ती प्रयोग में। अस्थिरता सिंक्रनाइज़ करने का एक कमजोर रूप है .. अगर किसी चर को 1 थ्रेड द्वारा लिखा जा रहा है और कई थ्रेडों द्वारा पढ़ा जाता है तो यह सुनिश्चित करने के लिए ठीक है कि लिखने को तत्काल देखा जाता है .. – bwawok

2

आप इस मामले में अस्थिरता का उपयोग कर सकते हैं।आपको वैरिएबल तक पहुंच के आसपास अस्थिर, सिंक्रनाइज़ेशन की आवश्यकता होगी या कुछ समान तंत्र (जैसे परमाणु संदर्भ) की गारंटी होगी कि असाइनमेंट थ्रेड पर किए गए परिवर्तन वास्तव में रीडिंग थ्रेड पर दिखाई दे रहे हैं। स्पष्ट करने के लिए, अपने कोड गलत के रूप में यह खड़ा है, यह सोचते हैं दो अलग धागे फोन assign() और use() है:

+0

लेकिन यह कैसे ख्याल रखता है कि ऑब्जेक्ट को निर्दिष्ट करने वाला थ्रेड * ऑब्जेक्ट का उपयोग करके थ्रेड * से पहले चलाएगा? – BalusC

+0

मुझे सिंक्रनाइज़ेशन की आवश्यकता क्यों है? अस्थिर के रूप में घोषित पर्याप्त नहीं है? – Tiyoal

+0

@Tiyoal - वह एक या/या है। आपको उन विकल्पों में से एक का उपयोग करने की आवश्यकता है। – Robin

0

यहाँ कुछ भ्रामक टिप्पणी नहीं है।

volatile के अभाव में, या कोई अन्य होता है-पहले संबंध (उदाहरण के लिए, तुल्यकालन एक आम ताला पर) assign() में myObject के लिए किसी भी लिखने धागा बुला use() द्वारा देखा जा करने के लिए गारंटी नहीं है - तुरंत नहीं, नहीं में एक समय पर फैशन, और वास्तव में कभी नहीं।

हां, volatile इसे सही करने का एक तरीका है (यह मानना ​​गलत व्यवहार है - ऐसी परिस्थितियां हैं जहां आपको इसकी परवाह नहीं है!)।

आप बिल्कुल सही हैं कि 'उपयोग' धागा myObject का कोई भी 'कैश्ड' मान देख सकता है, जिसमें इसे निर्माण समय पर आवंटित किया गया था और किसी भी मध्यवर्ती मूल्य (फिर से दूसरे बिंदुओं की अनुपस्थिति में)।

4

एक अस्थिर जावा चर की घोषणा का अर्थ है:

  • इस वेरिएबल का मान धागे की स्थानीय स्तर पर
  • चर में कार्य करता है जैसे कि यह एक सिंक्रनाइज़ ब्लॉक में संलग्न है के लिए प्रवेश कभी नहीं संचित किया जाएगा

अस्थिर की विशिष्ट और सबसे आम उपयोग है:

public class StoppableThread extends Thread { 
    private volatile boolean stop = false; 

    public void run() { 
    while (!stop) { 
     // do work 
    } 
    } 

    public void stopWork() { 
    stop = true; 
    } 
} 
1

मैंने volatile कीवर्ड को समझने की कोशिश करने में काफी समय बिताया है। मुझे लगता है कि @aleroot ने दुनिया में सबसे अच्छा और सरल उदाहरण दिया है।

इस में (मेरे जैसे :-)) नौसिखियों के लिए मेरी स्पष्टीकरण बारी है:

Scenario1: मानते हुए stop अस्थिर के रूप में घोषित नहीं किया गया है तो किसी दिए गए धागा करता है और 'सोचता है' के बाद:

  1. stopWork() कहा जाता है: मैं stoptrue को
  2. महान सेट करने के लिए, मैं अपने स्थानीय ढेर में यह किया अब मैं है JVM के मुख्य ढेर अद्यतन करने के लिए।
  3. ओह, जेवीएम मुझे सीपीयू में किसी अन्य थ्रेड में रास्ता देने के लिए कहता है, मुझे थोड़ी देर के लिए रुकना है ...
  4. ठीक है, मैं वापस आ गया हूं। अब मैं अपने मूल्य के साथ मुख्य ढेर को अद्यतन कर सकता हूं। अपडेट कर रहा है ...

Scenario2: अब stop जाने अस्थिर घोषित किया:

  1. stopWork() कहा जाता है: मैं stoptrue को
  2. महान सेट करने के लिए, अब मैं अपने स्थानीय ढेर में यह किया मुझे JVM का मुख्य ढेर अपडेट करना होगा।
  3. क्षमा करें दोस्तों, मुझे करना है (2) अब - मुझे बताया गया है कि यह volatile है। मुझे सीपीयू को थोड़ी देर पर कब्जा करना है ...
  4. मुख्य ढेर को अपडेट करना ...
  5. ठीक है, मैं कर रहा हूं। अब मैं उपज कर सकता हूं।

नहीं तुल्यकालन, बस एक साधारण विचार ...

सभी चर volatile सिर्फ मामले में क्यों घोषित करने के लिए नहीं है? परिदृश्य 2/चरण 3 के कारण। यह थोड़ा अक्षम है लेकिन नियमित सिंक्रनाइज़ेशन से अभी भी बेहतर है।

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

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