java - BufferedInputStream सीधे फ़ील्ड का उपयोग करने के बजाय किसी फ़ील्ड को स्थानीय चर में कॉपी क्यों करता है




(3)

इसका कारण यह है कि वर्ग BufferedInputStream को बहु-थ्रेडेड उपयोग के लिए डिज़ाइन किया गया है।

यहाँ, आप की घोषणा देखते हैं, जिसे मूल वर्ग में रखा गया है FilterInputStream :

protected volatile InputStream in;

चूंकि यह protected , इसलिए इसका मान किसी भी उपवर्ग द्वारा बदला जा सकता है, जिसमें BufferedInputStream और इसके उपवर्ग शामिल हैं। इसके अलावा, इसे volatile घोषित किया जाता है, जिसका अर्थ है कि यदि कोई धागा चर के मूल्य को बदलता है, तो यह परिवर्तन तुरंत अन्य सभी थ्रेड्स में परिलक्षित होगा। यह संयोजन खराब है, क्योंकि इसका मतलब है कि वर्ग BufferedInputStream पास कोई तरीका नहीं है कि वह नियंत्रित या जान सके कि कब बदला गया है। इस प्रकार, मान को अशक्त के लिए चेक और BufferedInputStream::getInIfOpen में रिटर्न स्टेटमेंट के बीच भी बदला जा सकता है, जो प्रभावी रूप से चेक को बेकार बना देता है। स्थानीय चर input में इसे कैश करने के लिए केवल एक बार के मूल्य को पढ़कर, विधि BufferedInputStream::getInIfOpen अन्य थ्रेड्स से परिवर्तन के खिलाफ सुरक्षित है, क्योंकि स्थानीय चर हमेशा एक ही धागे के स्वामित्व में होते हैं।

BufferedInputStream::close में एक उदाहरण है, जो शून्य in सेट in है:

public void close() throws IOException {
    byte[] buffer;
    while ( (buffer = buf) != null) {
        if (bufUpdater.compareAndSet(this, buffer, null)) {
            InputStream input = in;
            in = null;
            if (input != null)
                input.close();
            return;
        }
        // Else retry in case a new buf was CASed in fill()
    }
}

यदि BufferedInputStream::close BufferedInputStream::getInIfOpen को किसी अन्य थ्रेड द्वारा कॉल किया जाता है, जबकि BufferedInputStream::getInIfOpen को निष्पादित किया जाता है, तो यह ऊपर वर्णित दौड़ की स्थिति में परिणाम होगा।

जब मैंने java.io.BufferedInputStream.getInIfOpen() से स्रोत कोड पढ़ा, तो मैं इस बारे में उलझन में हूं कि इसने इस तरह कोड क्यों लिखा:

/**
 * Check to make sure that underlying input stream has not been
 * nulled out due to close; if not return it;
 */
private InputStream getInIfOpen() throws IOException {
    InputStream input = in;
    if (input == null)
        throw new IOException("Stream closed");
    return input;
}

यह नीचे की तरह सीधे क्षेत्र चर का उपयोग करने के बजाय उपनाम का उपयोग क्यों कर रहा है:

/**
 * Check to make sure that underlying input stream has not been
 * nulled out due to close; if not return it;
 */
private InputStream getInIfOpen() throws IOException {
    if (in == null)
        throw new IOException("Stream closed");
    return in;
}

क्या कोई उचित स्पष्टीकरण दे सकता है?


मेरा मानना ​​है कि स्थानीय चर input वर्ग चर in कैप्चर करना असंगत व्यवहार को रोकने के लिए है यदि getInIfOpen() चल रहा है, तो किसी अन्य थ्रेड द्वारा परिवर्तित किया जाता है।

ध्यान दें कि का मालिक मूल वर्ग है और इसे final रूप में चिह्नित नहीं करता है।

इस पैटर्न को कक्षा के अन्य हिस्सों में दोहराया जाता है और यह उचित रक्षात्मक कोडिंग लगता है।


यह एक ऐसा छोटा कोड है, लेकिन, सैद्धांतिक रूप से, बहु-थ्रेडेड वातावरण में, तुलना के बाद सही बदल सकता है, इसलिए विधि कुछ ऐसा लौटा सकती है जो यह जांच नहीं करता था (यह null लौट सकता है, इस प्रकार यह सटीक कार्य कर रहा था) रोकने का मतलब है)।






bufferedinputstream