2009-06-02 16 views
10

ThreadLocal की मेरी सीमित समझ यह है कि इसमें resource leak issues है। मैं इस समस्या को WeakReferences के उचित उपयोग के माध्यम से थ्रेडलोकल (हालांकि मैंने इस बिंदु को गलत समझा होगा) के उचित उपयोग के माध्यम से उपचार किया जा सकता है।) यदि मैं मौजूद हूं तो थैकलोकल के साथ थ्रेडलोकल का सही उपयोग करने के लिए मुझे बस एक पैटर्न या उदाहरण पसंद आएगा। उदाहरण के लिए, इस कोड स्निपेट में वीक रेफरेंस कहां पेश किया जाएगा?थ्रेडलोकल संसाधन लीक और वीक रेफरेंस

static class DateTimeFormatter { 
    private static final ThreadLocal<SimpleDateFormat> DATE_PARSER_THREAD_LOCAL = new ThreadLocal<SimpleDateFormat>() { 
     protected SimpleDateFormat initialValue() { 
      return new SimpleDateFormat("yyyy/MM/dd HH:mmz"); 
     } 
    }; 
    public String format(final Date date) { 
     return DATE_PARSER_THREAD_LOCAL.get().format(date); 
    } 
    public Date parse(final String date) throws ParseException 
    { 
     return DATE_PARSER_THREAD_LOCAL.get().parse(date); 
    } 
} 
+1

तुम क्यों लगता है कि यह है है संसाधन मुद्दे? कारण मैं पूछता हूं क्योंकि मेरे अनुभव में, मुझे कोई समस्या नहीं है। –

+0

कृपया कुछ पृष्ठभूमि प्रदान करें कि आपको क्यों लगता है कि स्मृति मेमोरी है। – erickson

+0

अपडेट किया गया। कृपया ऊपर "संसाधन रिसाव मुद्दों" लिंक देखें। –

उत्तर

27

ThreadLocal आंतरिक रूप से WeakReference का उपयोग करता है।यदि ThreadLocal को दृढ़ता से संदर्भित नहीं किया गया है, तो यह कचरा एकत्रित होगा, भले ही विभिन्न धागे के मूल्य ThreadLocal के माध्यम से संग्रहीत हों।

इसके अतिरिक्त, ThreadLocal मान वास्तव में Thread में संग्रहीत हैं; यदि कोई धागा मर जाता है, तो ThreadLocal के माध्यम से उस धागे से जुड़े सभी मूल्य एकत्र किए जाते हैं।

यदि आपके पास ThreadLocal अंतिम श्रेणी के सदस्य के रूप में है, तो यह एक मजबूत संदर्भ है, और इसे तब तक एकत्र नहीं किया जा सकता जब तक कि कक्षा अनलोड नहीं हो जाती। लेकिन इस तरह कोई वर्ग सदस्य काम करता है, और इसे स्मृति रिसाव नहीं माना जाता है।


अद्यतन: उद्धृत समस्या केवल जब एक ThreadLocal में संग्रहीत मूल्य दृढ़ता से है कि एक परिपत्र संदर्भ की ThreadLocal — तरह का संदर्भ खेलने में आता है।

इस मामले में, मान (SimpleDateFormat), ThreadLocal के पीछे कोई संदर्भ नहीं है। इस कोड में कोई स्मृति रिसाव नहीं है।

+0

लीक करते समय जब थ्रेड-लोकल वैल्यू (अप्रत्यक्ष रूप से) संदर्भित करता है तो थ्रेडलोकल अभी भी सूर्य के कार्यान्वयन में एक बग है। मुझे यकीन नहीं है कि अगर हर्मोनी में पागल बॉब ली के कार्यान्वयन में एक ही समस्या है। –

+0

क्या यह थ्रेडलोकल, या एप्लिकेशन और थ्रेडलोकल के उपयोग में एक बग है? मैंने अभी तक इसमें भाग नहीं लिया है (और मैं थ्रेडलोकल से बचने की कोशिश करता हूं), इसलिए मुझे अभी भी यकीन नहीं है। – erickson

+0

ध्यान दें कि एक Servlet वातावरण में आपको थ्रेडलोकल को साफ़ करने के लिए एक सर्वलेट फ़िल्टर का उपयोग करने की आवश्यकता है, यदि आप ऐसा नहीं करते हैं तो आपको redeploys पर बहुत से रिसाव होंगे –

3

वहाँ ऐसी समस्या नहीं होना चाहिए।

एक थ्रेड का थ्रेडलोकल संदर्भ केवल तब तक अस्तित्व में परिभाषित किया जाता है जब तक कि संबंधित धागा जीवित रहता है (जावाडोक देखें) - या धागा जीवित होने के बाद, एक और तरीका डालें, अगर थ्रेडलोकल उस ऑब्जेक्ट का एकमात्र संदर्भ था , तो वस्तु कचरा संग्रह के लिए योग्य हो जाती है।

तो या तो आपको एक वास्तविक बग मिला है और इसे रिपोर्ट करना चाहिए, या आप कुछ और गलत कर रहे हैं!

+0

जब आप किसी ऐप सर्वर/कंटेनर के अंदर चल रहे हों तो उस मामले पर विचार करें जो आपके एप्लिकेशन को अनलोड कर सकता है (इंस्टॉल करने, कहने के लिए, एक अलग संस्करण) लेकिन एक नई ऐप रिलीज के लिए थ्रेड का उपयोग करना जारी रखता है। –

1

@Neil Coffey ने जो कहा, उसे जोड़ने के लिए, यह तब तक कोई समस्या नहीं होनी चाहिए जब तक आपका थ्रेडलोकल उदाहरण स्थैतिक न हो। चूंकि आप एक स्थिर उदाहरण पर कॉल() को कॉल करते रहते हैं, तो इसे हमेशा आपके सरल दिनांक फ़ॉर्मेटर के समान संदर्भ रखना चाहिए। इसलिए, जैसा कि नील ने कहा था, जब थ्रेड समाप्त हो जाता है, तो साधारण दिनांक स्वरूपक का एकमात्र उदाहरण कचरा संग्रह के लिए योग्य होना चाहिए।

यदि आपके पास संख्या या डिबगिंग का कोई अन्य रूप है जो इस परिचय संसाधन मुद्दों को दिखाता है, तो यह एक और कहानी है। लेकिन मुझे विश्वास है कि यह एक समस्या नहीं होनी चाहिए।

10

मुझे लगता है कि आप इन हुप्स के माध्यम से कूद रहे हैं क्योंकि SimpleDateFormat थ्रेड-सुरक्षित नहीं है।

जबकि मुझे पता है कि मैं ऊपर आपकी समस्या को हल नहीं कर रहा हूं, क्या मैं सुझाव दे सकता हूं कि आप अपनी तिथि/समय के काम के लिए Joda देखें? जोडा में थ्रेड-सुरक्षित दिनांक/समय स्वरूपण तंत्र है। आप जोडा एपीआई सीखने में अपना समय बर्बाद नहीं करेंगे, क्योंकि यह नई मानक तिथि/समय एपीआई प्रस्ताव की नींव है।

+1

+1: मैंने इसके बारे में भी सोचा नहीं था। यह एक उचित शर्त है कि यह मामला है, अगर इस ओपी के लिए नहीं, तो संभवतः किसी और के लिए। –

0

आपके उदाहरण में थ्रेडलोकल का उपयोग करने में कोई समस्या नहीं होनी चाहिए।

थ्रेड स्थानीय (और सिंगलेट्स भी!) एक समस्या बन जाते हैं जब थ्रेड लोकल क्लासलोडर द्वारा लोड किए गए उदाहरणों पर सेट किए जाते हैं जिन्हें बाद में अनलोड किया जाता है। एक सर्वलेट कंटेनर (टोमकैट की तरह) में एक सामान्य स्थिति:

  1. वेबपैप अनुरोध प्रसंस्करण के दौरान एक थ्रेड स्थानीय सेट करता है।
  2. धागा कंटेनर द्वारा प्रबंधित किया जाता है।
  3. वेबपैप को बेरोजगार होना चाहिए।
  4. वेबएप का क्लासलोडर कचरा नहीं जा सकता है, क्योंकि एक संदर्भ शेष है: थ्रेड स्थानीय से उदाहरण के लिए अपनी कक्षा में इसके क्लासलोडर तक।

सिंगलेट्स (java.sql.DriverManger और वेबपैड द्वारा प्रदान किए गए जेडीबीसी ड्राइवर) के साथ समान।

तो विशेष रूप से ऐसे वातावरण से बचें जो आपके पूर्ण नियंत्रण में नहीं हैं!

+3

नहीं, प्रारूपक धागे सुरक्षित नहीं हैं। एक उदाहरण के पार्स विधि का आह्वान करने वाले एकाधिक थ्रेड एक आपदा है। – erickson

+0

हालांकि थ्रेडलोकल्स के नुकसान के बारे में अच्छे अंक! – erickson

+0

ठीक है, SimpleDateFormat के बारे में सोचा नहीं था, लेकिन थ्रेडलोकल के साथ वैसे भी कोई समस्या नहीं होनी चाहिए। –

2

मुझे एहसास है कि यह आपके प्रश्न का सख्ती से जवाब नहीं है, लेकिन एक सामान्य नियम के रूप में मैं ThreadLocal का उपयोग करके बैठने की सलाह नहीं दूंगा जहां अनुरोध/बातचीत के अंत में कोई स्पष्ट आंसू नहीं है। क्लासिक इस प्रकार की चीज को सर्वलेट कंटेनर में कर रहा है, पहली नज़र में यह ठीक लगता है, लेकिन चूंकि धागे को पूल किया जाता है, इसलिए प्रत्येक अनुरोध संसाधित होने के बाद भी ThreadLocal संसाधन पर लटकने के साथ यह एक मुद्दा बन जाता है।

सुझाव:

  1. के रूप में किसी को पहले से ही सुझाव दिया है प्रत्येक बातचीत के अंत में ThreadLocal स्पष्ट करने के लिए प्रत्येक बातचीत के लिए इसी तरह के आवरण के एक फिल्टर का उपयोग करें
  2. आप एक विकल्प का इस्तेमाल कर सकते FastDateFormat from commons-lang या Joda तरह SimpleDateFormat को
  3. हर बार जब आपको इसकी आवश्यकता हो तो बस एक नया SimpleDateFormat बनाएं। बेकार मैं जानता हूँ कि लगता है, लेकिन सबसे अनुप्रयोगों में आप सिर्फ अंतर धागा उपयोग करने के बाद स्थानीय नोटिस नहीं होगा
0

स्वच्छ, ऐसा करने के लिए सर्वलेट फ़िल्टर जोड़ें:

 
protected ThreadLocal myThreadLocal = new ThreadLocal(); 

public void doFilter (ServletRequest req, ServletResponse res, chain) throws IOException, ServletException { 
    try { 
     // Set ThreadLocal (eg. to store heavy computation result done only once per request) 
     myThreadLocal.set(context()); 

     chain.doFilter(req, res); 
    } finally { 
     // Important : cleanup ThreaLocal to prevent memory leak 
     userIsSmartTL.remove(); 
    } 
}