6

अच्छी तरह बहुप्रशंसित पुस्तक JCIP इस बारे में ThreadLocal उपयोग का कहना है:कैसे ThreadLocal उपयोग पुनर्प्रयोग को कम करता है

यह एक लाइसेंस वैश्विक चर का उपयोग करने के रूप में या के एक साधन के रूप में अपनी धागा कारावास संपत्ति मानकर ThreadLocal दुरुपयोग करने के लिए आसान है "छुपा" विधि तर्क बनाते हैं। थ्रेड-स्थानीय चर पुन: प्रयोज्यता से अलग हो सकते हैं और कक्षाओं के बीच छिपे हुए युग्मन पेश कर सकते हैं, और इसलिए देखभाल के साथ उपयोग किया जाना चाहिए।

क्या यह कह रही है कि थ्रेड-स्थानीय चर पुनर्प्रयोग को कम करने और वर्गों के बीच छिपा कपलिंग्स लागू कर सकते हैं द्वारा मतलब है?

+0

मैं एक सरल कोड उदाहरण के साथ अपने जवाब देने के लिए एक संपादन किया है। – Tudor

उत्तर

10

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

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

class Foo { 
    public static ThreadLocal<Long> localSum = new ThreadLocal<Long>() { 
     public Long initialValue() { 
      return new Long(0);   
     } 
    }; 
} 

class Task implements Callable<Long> { 

    private int start = 0; 
    private int end = 0;  

    public Task(int start, int end) { 
     this.start = start; 
     this.end = end; 
    } 

    public Long call() { 
     for(int i = start; i < end; i++) { 
      Foo.localSum.set(Foo.localSum.get() + i); 
     } 
     return Foo.localSum.get(); 
    } 
} 

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

हालांकि यह एक सरल उदाहरण उद्देश्य पर जटिल है, तो आप "छिपा" वैश्विक चर के खतरों देख सकते हैं। यह भी पठनीयता को प्रभावित करता है के बाद से किसी और पढ़ने कोड भी वर्ग Foo के लिए खोज और देखो क्या Foo.localSum की परिभाषा है करना होगा। आपको अपनी कक्षाओं को यथासंभव स्वयं निहित रखना चाहिए।

+0

@ शुभरा - ट्यूडर का जवाब पर्याप्त स्पष्ट नहीं है? आपको विशेष रूप से 'उदाहरण कोड' की आवश्यकता क्यों है? –

+0

@ शुभरा: मैंने एक साधारण कोड उदाहरण के साथ एक संपादन किया है। – Tudor

3

एक ThreadLocal धागा प्रति घोषित किया जाता है - इस से शुरू - - आम तौर पर एक क्षेत्र है कि वर्ग की वस्तु प्रति घोषित किया जाता है कोई बात बिगड़ जाए सकते हैं कि अगर ThreadLocal दुरुपयोग किया जाता है की एक पूरी बहुत कुछ हो सकता है।

यदि कोई थ्रेड एकाधिक ऑब्जेक्ट्स (या तो एकल वर्ग या एकाधिक कक्षाओं) से गुजरता है, तो ThreadLocal इस थ्रेड द्वारा उपयोग किया जाता है, इन सभी उदाहरणों में एक ही उदाहरण है। यह युग्मन बीजी बात कर रहा है। जिस क्षण एक युग्मन होता है - पुन: प्रयोज्यता मुश्किल हो जाती है और त्रुटि प्रवण होती है।

+0

ThreadLocal के बारे में जावा दस्तावेज़ का कहना है कि आम तौर पर ThreadLocals निजी स्थिर लेकिन 'स्थिर' ThreadLocal द्वारा लागू नहीं की है होना चाहिए। तो तकनीकी रूप से थ्रेडलोकल प्रति थ्रेड प्रति उदाहरण हो सकता है। हालांकि आपका दूसरा पैराग्राफ सवाल का जवाब बहुत अच्छी तरह से करता है। – Inquisitive

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