2010-08-30 26 views
6

केवल जावा 5 और ऊपर। एक मल्टीप्रोसेसर साझा-मेमोरी कंप्यूटर मानें (आप शायद अभी एक का उपयोग कर रहे हैं)।जावा सिंक्रनाइज़ किए गए कीवर्ड कैश को फ्लश करता है?

यहाँ एक सिंगलटन के आलसी आरंभीकरण के लिए एक कोड है:

public final class MySingleton { 
    private static MySingleton instance = null; 
    private MySingleton() { } 
    public static MySingleton getInstance() { 
    if (instance == null) { 
     synchronized (MySingleton.class) { 
     if (instance == null) { 
      instance = new MySingleton(); 
     } 
     } 
    } 
    return instance; 
    } 
} 

instancevolatile आदेश getInstance() के रूप में (फिर से लिखने से अनुकूलक को रोकने के लिए जो एक अनुक्रमिक में सही होगा में घोषित किया जाना है क्या कार्यक्रम):

public static MySingleton getInstance() { 
    if (instance == null) { 
    synchronized (MySingleton.class) { 
     // instance must be null or we wouldn't be here (WRONG!) 
     instance = new MySingleton(); 
    } 
    } 
} 

अनुकूलक मान लिया जाये कि अगर instancevolatile घोषित नहीं किया गया है, कोड पुनर्लेखन नहीं है कि यह अभी भी याद करने के लिए प्लावित होने की गारंटी है जब synchronized ब्लॉक बाहर निकला है, और synchronized ब्लॉक दर्ज किया गया है, तो स्मृति से पढ़ें?

संपादित करें: मैं getInstance() स्थिर बनाने के लिए भूल गया था। मुझे नहीं लगता कि उत्तर की वैधता में परिवर्तन होता है; आप सब जानते थे कि मेरा क्या मतलब था।

+0

संकेत: आप कोड को अलग करने के लिए 'javap -c com.example.ClassName' का उपयोग कर सकते हैं ताकि आप यह जांच सकें कि इसे कैसे संकलित किया गया है और यदि संकलक ने एक या दूसरे को बदल दिया/अनुकूलित किया है। मैंने जेडीके 1.6 में से एक के साथ यह आपके लिए जांच की है और कंपाइलर ने नेस्टेड 'if' को नहीं हटाया है। – BalusC

+1

जावप का उपयोग करना दिलचस्प है, लेकिन जावैक में ऑप्टिमाइज़र आमतौर पर बहुत खराब होता है। जान - बूझकर। वास्तविक अनुकूलक रनटाइम पर जेआईटी कंपाइलर में है। – Darron

+0

मैं केवल उत्तर में से एक को "उत्तर" के रूप में जांचने के लिए क्षमा चाहता हूं। उन सभी को अभी तक चेक करने के लायक हैं, लेकिन यह केवल मुझे एक की जांच करने देता है। –

उत्तर

15

हाँ, instancevolatile घोषित किया जाना चाहिए। फिर भी, यह सलाह दी जाती है कि डबल-चेक किए गए लॉकिंग का उपयोग न करें। यह (या सटीक होना, जावा मेमोरी मॉडल) में गंभीर दोष होता था जिसने आंशिक रूप से कार्यान्वित वस्तुओं के प्रकाशन की अनुमति दी थी। यह जावा 5 में तय किया गया है, फिर भी डीसीएल एक अप्रचलित मुहावरे है और इसके लिए अब और उपयोग करने की आवश्यकता नहीं है - इसके बजाय lazy initialization holder idiom का उपयोग करें।

Java Concurrency in Practice से, खंड 16.2:

DCL साथ वास्तविक समस्या धारणा है कि सबसे बुरी बात यह है कि हो सकता है जब तुल्यकालन के बिना एक साझा ऑब्जेक्ट संदर्भ पढ़ने ग़लती से (एक बासी मूल्य को देखने के लिए इस मामले में है , null); उस स्थिति में डीसीएल मुहावरे लॉक के साथ फिर से प्रयास करके इस जोखिम के लिए क्षतिपूर्ति करता है। लेकिन सबसे बुरी स्थिति वास्तव में काफी खराब है - संदर्भ के वर्तमान मूल्य को देखना संभव है लेकिन ऑब्जेक्ट के राज्य के लिए मूल्यवान मान, जिसका अर्थ यह है कि ऑब्जेक्ट को अमान्य या गलत स्थिति में देखा जा सकता है।

झामुमो में बाद के परिवर्तन (जावा 5.0 और बाद में) काम करने के लिए अगरresourcevolatile किया जाता है DCL सक्षम किया है, और इस बात का प्रदर्शन प्रभाव छोटा है के बाद से volatile पढ़ता केवल थोड़ा आम तौर पर और अधिक महंगा nonvolatile पढ़ता है। हालांकि, यह एक मुहावरे है जिसका उपयोगिता काफी हद तक पारित हो गई है - जो बल इसे प्रेरित करते हैं (धीमी असंतुलित सिंक्रनाइज़ेशन, धीमी जेवीएम स्टार्टअप) अब खेल में नहीं हैं, जिससे इसे अनुकूलन के रूप में कम प्रभावी बना दिया जाता है। आलसी प्रारंभिक धारक मुहावरे एक ही लाभ प्रदान करता है और समझना आसान है।

+1

+1 बहुत दिलचस्प है। मैं हमेशा stackoverflower द्वारा outsmarted हूँ। यह एक कभी खत्म होने वाली विनम्रता अभ्यास नहीं है। – gawi

+1

यदि एडस्गर डिजस्ट्रा अभी भी हमारे साथ थे, तो शायद वह टिप्पणी करेंगे कि अगर विशेषज्ञ प्रोग्रामर हमेशा स्टैक ओवरफ्लो से बाहर निकलते हैं, तो पेशे खराब स्थिति में होती है। –

+0

धारक वर्ग मुहावरे केवल सिंगलेट के लिए काम करता है। आलसी शुरुआत के सामान्य तंत्र नहीं। – irreputable

1

हाँ, उदाहरण का उपयोग करते हुए अस्थिर होने की जरूरत है देखें दोबारा जांच जावा में ताला लगा, क्योंकि अन्यथा MySingleton के प्रारंभ प्रणाली के बाकी हिस्सों के लिए एक आंशिक रूप से निर्माण वस्तु का पर्दाफाश हो सकता है। यह भी सच है कि जब वे "सिंक्रनाइज़" कथन तक पहुंचते हैं तो थ्रेड सिंक हो जाएंगे, लेकिन इस मामले में बहुत देर हो चुकी है।

Wikipedia और कुछ अन्य स्टैक ओवरफ़्लो प्रश्नों में "डबल-चेक लॉकिंग" की अच्छी चर्चा है, इसलिए मैं इसके बारे में पढ़ने की सलाह दूंगा। मैं तब तक इसका उपयोग नहीं करने की सलाह दूंगा जब तक प्रोफाइलिंग इस विशेष कोड में प्रदर्शन की वास्तविक आवश्यकता को प्रदर्शित न करे।

+0

(javaworld लेख से) एक सामान्य रूप से सुझाया गया गैरफिक्स कुछ क्लास के संसाधन क्षेत्र को अस्थिर के रूप में घोषित करना है। हालांकि, जब जेएमएम अस्थिर चर को एक-दूसरे के संबंध में पुन: व्यवस्थित करने से रोकता है और यह सुनिश्चित करता है कि उन्हें तुरंत मुख्य स्मृति में फहराया जाता है, फिर भी यह अल्टोवाटाइल पढ़ने और लिखने के संबंध में अस्थिर चर के पढ़ने और लिखने की अनुमति देता है। इसका मतलब है - जब तक कि सभी संसाधन फ़ील्ड अस्थिर नहीं होते हैं - थ्रेड बी अभी भी कन्स्ट्रक्टर के प्रभाव को समझ सकता है क्योंकि संसाधन के बाद नए बनाए गए संसाधन को संदर्भित करने के लिए सेट किया गया है। – gawi

+1

यह जावा 5 में तय किया गया था, हालांकि यह इंगित करने लायक है कि पुराने वीएम में भी अस्थिर समस्या को ठीक नहीं करेगा। – samkass

1

जावा एकमात्र के आलसी आरंभीकरण के लिए एक सुरक्षित और अधिक पठनीय मुहावरा नहीं है:

class Singleton { 

    private static class Holder { 
    static final Singleton instance = create(); 
    } 

    static Singleton getInstance() { 
    return Holder.instance; 
    } 

    private Singleton create() { 
    ⋮ 
    } 

    private Singleton() { } 

} 

आप अधिक वर्बोज़ की दोबारा जांच कर लॉकिंग पैटर्न का उपयोग है, तो खाने volatile घोषित करने के लिए है, अन्य के रूप में पहले से ही नोट किया गया है।

0

नहीं। यह अस्थिर नहीं होना चाहिए। How to solve the "Double-Checked Locking is Broken" Declaration in Java?

पिछले प्रयास सभी क्योंकि आप जावा धोखा और वाष्पशील/सिंक से बचने कर सकते हैं, जावा आप को धोखा देने और आप वस्तु की एक गलत दृश्य दे सकते हैं असफल रहा। हालांकि नया final अर्थशास्त्र समस्या हल करता है। यदि आपको ऑब्जेक्ट संदर्भ मिलता है (सामान्य पढ़ने से), तो आप सुरक्षित रूप से final फ़ील्ड पढ़ सकते हैं।

+1

फिर भी, आलसी प्रारंभिक धारक मुहावरे एक स्पष्ट तरीके से, कम कोड (इस प्रकार त्रुटियों के लिए कम मौका) और स्पष्ट सिंक्रनाइज़ेशन की आवश्यकता के बिना प्राप्त करता है। –

+0

जो केवल सिंगलेट के लिए काम करता है। रनटाइम पर वस्तुओं की गतिशील संख्या को आलसी बनाने के लिए नहीं। – irreputable

+1

यह प्रश्न स्पष्ट रूप से सिंगलेट के बारे में है। – erickson