मुझे थ्रेडलोक चर का उपयोग कब और कैसे करना चाहिए?


875

मुझे एक ThreadLocalचर का उपयोग कब करना चाहिए ?

इसका उपयोग कैसे किया जा सकता है?


11
यदि आप थ्रेडलॉक का उपयोग कर रहे हैं, तो उस पर कभी भी एक आवरण न लिखें !!! प्रत्येक और हर डेवलपर जो वैरिएबल का उपयोग करना चाहता है, उसे यह पता होना चाहिए कि यह 'थ्रेडलॉक' है
एक बग

2
@ नोटबग यदि आप स्पष्ट हैं, तो आप अपने चर को नाम दे सकते हैं ताकि ऐसा हो कि आप थ्रेडलोक मान के साथ काम कर रहे हों, जैसे RequestUtils.getCurrentRequestThreadLocal()। हालांकि यह कहना बहुत सुरुचिपूर्ण नहीं है, लेकिन यह इस तथ्य से उपजा है कि थ्रेडलोक स्वयं ज्यादातर मामलों में बहुत सुंदर नहीं है।
whirlwin

@ साशा थ्रेडलोक का उपयोग निष्पादन ट्रेस को स्टोर करने के लिए किया जा सकता है
गौरव

जवाबों:


864

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

उदाहरण के लिए:

public class Foo
{
    // SimpleDateFormat is not thread-safe, so give one to each thread
    private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue()
        {
            return new SimpleDateFormat("yyyyMMdd HHmm");
        }
    };

    public String formatIt(Date date)
    {
        return formatter.get().format(date);
    }
}

प्रलेखन


160
सिंक्रोनाइज़ेशन या थ्रेडलोकल का एक अन्य विकल्प वैरिएबल को एक वैरिएबल वैरिएबल बनाना है। स्थानीय संस्करण हमेशा थ्रेड सुरक्षित होते हैं। मुझे लगता है कि डेटफ़ॉर्मेट्स को स्थानीय बनाने के लिए यह बुरा अभ्यास है क्योंकि वे बनाने के लिए महंगे हैं, लेकिन मैंने इस विषय पर ठोस मैट्रिक्स कभी नहीं देखा है।
जुलिएन चास्तांग

18
हैकिंग के लिए भुगतान करने के लिए यह उच्च कीमत है SimpleDateFormat। शायद थ्रेड-सुरक्षित विकल्प का उपयोग करना बेहतर है । यदि आप इस बात से सहमत हैं कि सिंगलनेट खराब हैं तो ThreadLocalऔर भी बुरा है।
अलेक्जेंडर रियाज़ोव

4
@overthink क्या थ्रेडलोकल स्टेटिक और फाइनल घोषित करने का कोई कारण है, मेरा मतलब है प्रदर्शन या कुछ और?
सचिन गोराडे

4
The ThreadLocal.get () विधि प्रत्येक थ्रेड के लिए ThreadLocal.initialValue () (एक बार) को कॉल करेगी, जिसका अर्थ है कि प्रत्येक थ्रेड के लिए एक SimpleDateFormat ऑब्जेक्ट बनाया गया है। यह बेहतर नहीं है तो बस SimpleDateFormat स्थानीय चर के रूप में (क्योंकि हम कचरा संग्रह मुद्दों से निपटने के लिए नहीं है)?
सुदीपदीनो

3
बस अपने SimpleDateFormat के लिए डबल ब्रेस इनिशियलाइज़ेशन का उपयोग न करने के लिए सावधान रहें क्योंकि यह एक अनाम वर्ग बनाएगा ताकि आपका क्लास लोडर कचरा एकत्र न कर सके। स्मृति रिसाव: नया SimpleDateFormat () {{applyPattern ("yyyyMMdd HHmm")}};
user1944408 15:27 पर

427

चूंकि किसी ThreadLocalदिए गए डेटा के संदर्भ में है Thread, आप थ्रेडिंग का उपयोग करके ThreadLocalएप्लिकेशन सर्वर में एस का उपयोग करते समय क्लास लोडिंग लीक के साथ समाप्त कर सकते हैं । आपको किसी भी ThreadLocals को साफ करने get()या 's' पद्धति set()का उपयोग करने के बारे में बहुत सावधान रहने की आवश्यकता है ।ThreadLocalremove()

यदि आप काम पूरा करने के बाद साफ नहीं करते हैं, तो यह किसी भी संदर्भित वेबपेज के हिस्से के रूप में लोड की गई कक्षाओं के लिए धारण किया जाता है और स्थायी ढेर में रहेगा । Webapp को Redeploying / undeploying Threadकरने से आपके webapp की कक्षा के प्रत्येक संदर्भ को साफ नहीं किया जाएगा (es) क्योंकि Threadआपके webapp के स्वामित्व में कुछ नहीं है। प्रत्येक क्रमिक परिनियोजन वर्ग का एक नया उदाहरण बनाएगा जो कभी भी कचरा एकत्र नहीं करेगा।

आप java.lang.OutOfMemoryError: PermGen spaceकुछ अपवादों के कारण स्मृति अपवादों से बाहर हो जाएंगे -XX:MaxPermSizeऔर बग को ठीक करने के बजाय संभवतः कुछ बढ़ जाएंगे ।

यदि आप इन समस्याओं का अनुभव करते हैं, तो आप यह निर्धारित कर सकते हैं कि कौन सा धागा और वर्ग ग्रहण के मेमोरी एनालाइज़र का उपयोग करके और / या फ्रैंक नोवेट के गाइड और फॉलोअप द्वारा इन संदर्भों को बनाए रख रहा है ।

अपडेट: एलेक्स वासेपुर के ब्लॉग प्रविष्टि की पुनः खोज जिसने मुझे कुछ ThreadLocalमुद्दों पर नज़र रखने में मदद की।


11
एलेक्स वासेपुर ने अपना ब्लॉग स्थानांतरित कर दिया। यहाँ स्मृति रिसाव लेख की एक वर्तमान कड़ी है।
केनस्टर

12
जूलियन लिंक को जिस धागे से यहाँ ले जाया गया है वह ऐसा लगता है, और पढ़ने लायक है ...
डोनल फेलो

28
यह एक उत्तर के लिए एक बहुत अधिक उत्थान है, जबकि जानकारीपूर्ण, किसी भी तरह से वास्तव में सवाल का जवाब नहीं देता है।
रॉबिन

8
अब जब PermGen को Java 8 द्वारा मार दिया गया है, तो क्या यह जवाब किसी भी तरह से बदल सकता है?
ईविल वॉशिंग मशीन

13
@ रोबिन: मैं असहमत हूं। सवाल यह है कि थ्रेडलोकल का सही तरीके से उपयोग कैसे किया जाए, किसी भी अवधारणा (थ्रेडलोकल) की पूरी समझ प्राप्त करने के लिए यह समझना भी महत्वपूर्ण है कि इसका उपयोग कैसे किया जाए और लापरवाही से उपयोग करने के जोखिम, और यही फिल का जवाब है। मुझे खुशी है कि उन्होंने उस बिंदु को कवर किया जो किसी अन्य उत्तर में शामिल नहीं है। वे सभी वोट अच्छी तरह से योग्य हैं। मेरा मानना ​​है कि SO को QA साइट होने की बजाय अवधारणाओं की समझ बनानी चाहिए।
सौरभ पाटिल

166

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

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


4
यह ठीक उसी तरह है जैसे एक्सपीओजेओ फ्रेमवर्क (www.expojo.com) एनोटेशन और इंजेक्शन के ओवरहेड की आवश्यकता के बिना ORM सत्र / PersistenceManager तक पहुंचने की अनुमति देता है। यह 'ऑब्जेक्ट इंजेक्शन' के बजाय 'थ्रेड इंजेक्शन' की तरह है। यह आवश्यकता (और उपरि) के बिना उन पर निर्भरता की पहुंच प्रदान करता है, जो उन्हें हर उस वस्तु में अंतःस्थापित करते हैं, जिन्हें उन निर्भरताओं की आवश्यकता हो सकती है। यह आश्चर्यजनक है कि 'लाइट वेट' आप क्लासिक DI (जैसे कि स्प्रिंग, आदि) के बजाय थ्रेड इंजेक्शन का उपयोग करते हुए DI फ्रेम बना सकते हैं
Volksman

27
मुझे इस आवश्यक उत्तर को खोजने के लिए इतना नीचे स्क्रॉल क्यों करना पड़ा !?
जेरेमी स्टीन

1
@ एस्स्को, आपकी परियोजना में, हैशकोड और बराबरी में थ्रेडलोक का उपयोग अनावश्यक है। एक बेहतर तरीका यह है कि जब भी जरूरत हो तो हैशकोड / समान फ़ंक्शन के संदर्भ को बनाएं या पास करें। इस तरह, आप थ्रेडलोकल हैक की आवश्यकता से पूरी तरह से बच सकते हैं।
पचेरियर


1
यह टीएल के उपयोग का सबसे अच्छा विवरण है।
डेक्सटर

52

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

यदि ऐसा नहीं है, तो आप एक अतिरिक्त पैरामीटर के साथ अपने विधि हस्ताक्षर को अव्यवस्थित नहीं करना चाह सकते हैं। एक गैर-थ्रेडेड दुनिया में, आप एक वैश्विक चर के बराबर जावा के साथ समस्या को हल कर सकते हैं। एक थ्रेडेड शब्द में, एक वैश्विक चर के बराबर एक थ्रेड-स्थानीय चर है।


13
इसलिए आपको थ्रेड लोकेल से उसी तरह बचना चाहिए जैसे आप ग्लोबल्स से बचते हैं। मैं संभवतः स्वीकार नहीं कर सकता कि आसपास मूल्यों को पारित करने के बजाय ग्लोबल्स (थ्रेड लोकल) बनाना ठीक है, लोगों को पसंद नहीं है क्योंकि यह अक्सर वास्तुकला की समस्याओं को प्रकट करता है जिसे वे ठीक नहीं करना चाहते हैं।
जुआन मेंडेस

10
शायद ... यह उपयोगी हो सकता है, हालांकि, यदि आपके पास एक विशाल, मौजूदा कोडबेस है जिसमें आपको एक नया डेटम जोड़ना होगा जिसे हर जगह पास करना होगा , जैसे सत्र संदर्भ, डीबी लेनदेन, लॉग-इन उपयोगकर्ता, आदि। ।
कॉर्नेल मेसन

6
डेटा के बजाय डेटा का उपयोग करने के लिए यश।
गहरे

इससे मुझे जिज्ञासा हुई। 'datum' is the singular form and 'data' is the plural form.
सिद्धार्थ

23

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

मैंने उल्लिखित पुस्तक से पाठ की प्रतिलिपि बनाई है, लेकिन कोड 3.10 गायब है क्योंकि यह समझना बहुत महत्वपूर्ण नहीं है कि थ्रेडलोक का उपयोग कहां किया जाना चाहिए।

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

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

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


18

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

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

अपनी वेब साइट पर, थ्रेडलोक का उपयोग करने के लिए मेरे पास कुछ और चर्चा और उदाहरण हैं जो ब्याज के भी हो सकते हैं।

कुछ लोग कुछ समवर्ती एल्गोरिदम में प्रत्येक थ्रेड के लिए "थ्रेड आईडी" संलग्न करने के तरीके के रूप में थ्रेडलोकल का उपयोग करने की वकालत करते हैं जहां आपको एक थ्रेड नंबर की आवश्यकता होती है (उदाहरण के लिए हेरली और शेविट देखें)। ऐसे मामलों में, जांचें कि आपको वास्तव में लाभ मिल रहा है!


क्या थ्रेडलोक का उपयोग निष्पादन ट्रेस को स्टोर करने के लिए किया जा सकता है
गौरव

13
  1. Java में थ्रेडलोक को JDK 1.2 पर पेश किया गया था लेकिन बाद में थ्रेडलोक वैरिएबल पर टाइप सेफ्टी शुरू करने के लिए JDK 1.5 में जेनरेट किया गया था।

  2. थ्रेडलोक थ्रेड स्कोप से जुड़ा हो सकता है, थ्रेड द्वारा निष्पादित सभी कोड थ्रेडलोक वैरिएबल तक पहुंच है, लेकिन दो थ्रेड एक दूसरे को नहीं देख सकते हैं थ्रेडलोक वैरिएबल।

  3. प्रत्येक थ्रेड थ्रेडलोक वैरिएबल की एक विशेष प्रति रखता है जो थ्रेड समाप्त होने या मरने के बाद सामान्य रूप से या किसी अपवाद के कारण कचरा संग्रह के योग्य हो जाता है, यह देखते हुए कि थ्रेडलोक वैरिएबल का कोई अन्य लाइव संदर्भ नहीं है।

  4. जावा में थ्रेडलोक चर आमतौर पर कक्षाओं में निजी स्थिर क्षेत्र होते हैं और थ्रेड के अंदर अपनी स्थिति बनाए रखते हैं।

और पढ़ें: जावा में थ्रेडलोक - उदाहरण कार्यक्रम और ट्यूटोरियल


क्या थ्रेडलोक का उपयोग निष्पादन ट्रेस को स्टोर करने के लिए किया जा सकता है
गौरव

11

प्रलेखन यह बहुत अच्छी तरह से कहता है: "प्रत्येक धागा जो [एक थ्रेड-लोकल वेरिएबल एक्सेस करता है] (इसके प्राप्त या सेट विधि के माध्यम से) की अपनी, स्वतंत्र रूप से वैरिएबल की प्रारंभिक प्रतिलिपि है"।

आप एक का उपयोग करते हैं जब प्रत्येक थ्रेड में किसी चीज़ की अपनी प्रतिलिपि होनी चाहिए। डिफ़ॉल्ट रूप से, थ्रेड्स के बीच डेटा साझा किया जाता है।


18
डिफ़ॉल्ट रूप से, स्थैतिक ऑब्जेक्ट या ऑब्जेक्ट थ्रेड के बीच स्पष्ट रूप से पारित हो जाते हैं, जहां दोनों थ्रेड्स एक ही ऑब्जेक्ट के संदर्भ में होते हैं, साझा किए जाते हैं। किसी थ्रेड में स्थानीय रूप से घोषित ऑब्जेक्ट साझा नहीं किए जाते हैं (वे थ्रेड के स्टैक के लिए स्थानीय हैं)। बस यही स्पष्ट करना चाहता था।
इयान वार्ले

@IVVarley: यह इंगित करने के लिए धन्यवाद। इसलिए यदि हमारे पास वेरिएबल है जो MyThread क्लास में घोषित और उपयोग किया जाता है, तो क्या हमें उस मामले में ThreadLocal की आवश्यकता है? उदाहरण: क्लास MyThread थ्रेड {String var1 ;, int var2; } इस मामले में var1 और var2 थ्रेड का अपना हिस्सा होगा और साझा नहीं किया जाता है, तो क्या हमें इस मामले में थ्रेडलोक की आवश्यकता है? मेरी समझ में पूरी तरह से गलत हो सकता है, कृपया मार्गदर्शन करें।
जयेश

4
यदि प्रत्येक थ्रेड किसी चीज़ की अपनी प्रतिलिपि चाहता है, तो उसे केवल स्थानीय क्यों नहीं घोषित किया जा सकता (जो हमेशा थ्रेड सुरक्षित है)?
सुदीपदीनो

@ sudeepdino008 आपके पास हमेशा उन थ्रेड्स के निर्माण का नियंत्रण नहीं है (
वेबप

10

Webapp सर्वर एक थ्रेड पूल रख सकता है, और ThreadLocalक्लाइंट से प्रतिक्रिया करने से पहले एक var को हटा दिया जाना चाहिए, इस प्रकार वर्तमान थ्रेड को अगले अनुरोध द्वारा पुन: उपयोग किया जा सकता है।


8

दो उपयोग के मामले जहां थ्रेडलोकल वैरिएबल का उपयोग किया जा सकता है -
1- जब हमें एक धागे के साथ राज्य को संबद्ध करने की आवश्यकता होती है (उदाहरण के लिए, एक उपयोगकर्ता आईडी या लेनदेन आईडी)। यह आमतौर पर एक वेब अनुप्रयोग के साथ होता है कि सर्वलेट में जाने वाले प्रत्येक अनुरोध में एक अद्वितीय लेनदेन होता है जो इसके साथ जुड़ा होता है।

// This class will provide a thread local variable which
// will provide a unique ID for each thread
class ThreadId {
    // Atomic integer containing the next thread ID to be assigned
    private static final AtomicInteger nextId = new AtomicInteger(0);

    // Thread local variable containing each thread's ID
    private static final ThreadLocal<Integer> threadId =
        ThreadLocal.<Integer>withInitial(()-> {return nextId.getAndIncrement();});

    // Returns the current thread's unique ID, assigning it if necessary
    public static int get() {
        return threadId.get();
    }
}

ध्यान दें कि यहाँ लैम्बडा एक्सप्रेशन का उपयोग करके InInitial विधि को लागू किया गया है।
2- एक अन्य उपयोग मामला तब है जब हम एक थ्रेड सुरक्षित उदाहरण चाहते हैं और हम सिंक्रनाइज़ेशन का उपयोग नहीं करना चाहते हैं क्योंकि सिंक्रनाइज़ेशन के साथ प्रदर्शन लागत अधिक है। ऐसा ही एक मामला है जब SimpleDateFormat का उपयोग किया जाता है। चूंकि SimpleDateFormat थ्रेड सुरक्षित नहीं है, इसलिए हमें इसे थ्रेड को सुरक्षित बनाने के लिए तंत्र प्रदान करना होगा।

public class ThreadLocalDemo1 implements Runnable {
    // threadlocal variable is created
    private static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue(){
            System.out.println("Initializing SimpleDateFormat for - " + Thread.currentThread().getName() );
            return new SimpleDateFormat("dd/MM/yyyy");
        }
    };

    public static void main(String[] args) {
        ThreadLocalDemo1 td = new ThreadLocalDemo1();
        // Two threads are created
        Thread t1 = new Thread(td, "Thread-1");
        Thread t2 = new Thread(td, "Thread-2");
        t1.start();
        t2.start();
    }

    @Override
    public void run() {
        System.out.println("Thread run execution started for " + Thread.currentThread().getName());
        System.out.println("Date formatter pattern is  " + dateFormat.get().toPattern());
        System.out.println("Formatted date is " + dateFormat.get().format(new Date()));
    } 

}

मैंने अभी भी थ्रेडलोकल का उपयोग करने का लाभ नहीं देखा है उदाहरण के लिए एक अद्वितीय आईडी बनाने के लिए यदि आपका उद्देश्य एक वृद्धिशील अद्वितीय पूर्णांक मान वापस करना है। `` `पब्लिक क्लास थ्रेडआईड {// अगले पूर्णांक आईडी वाले परमाणु पूर्णांक को निजी स्थिर अंतिम एटॉमिकइंटराइज़र सौंपा जाना है अगला = न्यू एटोमिकइंटर (0); // वर्तमान थ्रेड की यूनिक आईडी लौटाता है, यदि आवश्यक हो तो सार्वजनिक स्थैतिक int प्राप्त करें () {रिटर्न nextId..getAndIncrement (); }} `` `
Dashenswen

7

जावा 8 रिलीज के बाद से, इनिशियलाइज़ करने के लिए अधिक घोषणात्मक तरीका है ThreadLocal:

ThreadLocal<Cipher> local = ThreadLocal.withInitial(() -> "init value");

जावा 8 रिलीज तक आपको निम्नलिखित कार्य करने थे:

ThreadLocal<String> local = new ThreadLocal<String>(){
    @Override
    protected String initialValue() {
        return "init value";
    }
};

इसके अलावा, अगर क्लास के इंस्टेंटिएशन मेथड (कंस्ट्रक्टर, फैक्ट्री मेथड) का इस्तेमाल किया जाता है, जो ThreadLocalकोई पैरामीटर नहीं लेता है, तो आप बस मेथड रेफरेंस (जावा 8 में प्रस्तुत) का उपयोग कर सकते हैं:

class NotThreadSafe {
    // no parameters
    public NotThreadSafe(){}
}

ThreadLocal<NotThreadSafe> container = ThreadLocal.withInitial(NotThreadSafe::new);

ध्यान दें: मूल्यांकन आलसी है क्योंकि आप java.util.function.Supplierलैम्बडा पास कर रहे हैं जिसका मूल्यांकन केवल तब किया ThreadLocal#getजाता है जब कहा जाता है लेकिन मूल्य का पहले मूल्यांकन नहीं किया गया था।


5

आपको थ्रेडलोकल पैटर्न के साथ बहुत सावधान रहना होगा। फिल उल्लेख जैसे कुछ प्रमुख नीचे की ओर हैं, लेकिन एक जिसका उल्लेख नहीं किया गया था, यह सुनिश्चित करने के लिए है कि कोड जो थ्रेडलोकल संदर्भ सेट करता है, वह "पुनः प्रवेश नहीं है।"

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


2
यदि कोड इससे निपटने के लिए तैयार है, तो पुन: प्रवेश की समस्या नहीं है। प्रवेश पर, यह नोट करें कि क्या चर पहले से ही सेट है, और बाहर निकलने पर, इसके पिछले मूल्य (यदि कोई था) को पुनर्स्थापित करें, या इसे हटा दें (यदि नहीं)।
सुपरकैट

1
@ जेफ, यार, यह आपके लिखे हर कोड का सच है, न कि सिर्फ ThreadLocalपैटर्न का। यदि आप करते हैं F(){ member=random(); F2(); write(member); }और F2 एक नए मूल्य के साथ सदस्य को ओवरराइड करता है, तो जाहिर है write(member)अब आपके द्वारा random()संपादित किए गए नंबर नहीं लिखेंगे । यह वस्तुतः सामान्य ज्ञान है। इसी तरह, यदि आप करते हैं F(){ F(); }, तो अपने अनंत लूप के साथ जीडी किस्मत! यह हर जगह सच है और विशिष्ट नहीं है ThreadLocal
पचेरियर

@ जेफ़, कोड उदाहरण?
पचेरियर

5

कब?

जब कोई ऑब्जेक्ट थ्रेड-सुरक्षित नहीं होता है, तो सिंक्रनाइज़ेशन के बजाय जो स्केलेबिलिटी को बाधित करता है, प्रत्येक थ्रेड को एक ऑब्जेक्ट देता है और इसे थ्रेड स्कोप रखता है, जो थ्रेडलोक है। सबसे अधिक इस्तेमाल किया जाने वाला लेकिन थ्रेड-सुरक्षित ऑब्जेक्ट्स में से एक डेटाबेस कनेक्शन और JMSConnection हैं।

कैसे ?

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

मुझे लगता है कि log4j एमडीसी को बनाए रखने के लिए थ्रेडलोक का भी उपयोग करता है।


5

ThreadLocal उपयोगी है, जब आप कुछ ऐसा राज्य चाहते हैं जिसे विभिन्न थ्रेड्स के बीच साझा नहीं किया जाना चाहिए, लेकिन यह अपने पूरे जीवनकाल में प्रत्येक थ्रेड से सुलभ होना चाहिए।

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

उस ने कहा, मन में है कि ThreadLocalअनिवार्य रूप से वैश्विक राज्य का एक रूप है। नतीजतन, इसके कई अन्य निहितार्थ हैं और सभी अन्य संभावित समाधानों पर विचार करने के बाद ही इसका उपयोग किया जाना चाहिए।


जब तक आप इसे वैश्विक स्थिति नहीं बनाते हैं, तब तक ThreadLocals वैश्विक स्थिति नहीं है। वे व्यावहारिक रूप से हमेशा सुलभ स्टैक संसाधन हैं। आप अपने सभी तरीकों (जो मंदबुद्धि है) में उस चर को पास करने के साथ थ्रेड लोकल का अनुकरण कर सकते हैं; वह इसे वैश्विक स्थिति नहीं बनाता है ...
एनरकोइओ

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

यह बस वस्तु स्थिति का एक हिस्सा हो सकता है, विश्व स्तर पर उपयोग करने की आवश्यकता नहीं है। ज़रूर, आपको थोड़ा सा उपरी हिस्सा मिलता है, लेकिन अगर कई वस्तुओं के प्रति धागे में अलग-अलग स्थिति है, तो आप ThreadLocalऑब्जेक्ट फ़ील्ड के रूप में उपयोग कर सकते हैं ...
Enerccio

आप सही हे। मैंने संभवतः इसके कई दुरुपयोगों पर ठोकर खाई है ThreadLocal, जहां यह विश्व स्तर पर सुलभ था। जैसा कि आपने कहा, यह अभी भी दृश्यता को सीमित करने वाले एक वर्ग क्षेत्र के रूप में इस्तेमाल किया जा सकता है।
Dimos

4

यहां वास्तव में कुछ भी नया नहीं है, लेकिन मुझे आज पता चला कि ThreadLocalवेब एप्लिकेशन में बीन वैलिडेशन का उपयोग करते समय यह बहुत उपयोगी है। सत्यापन संदेश स्थानीयकृत हैं, लेकिन डिफ़ॉल्ट रूप से उपयोग Locale.getDefault()। आप Validatorकिसी भिन्न के साथ कॉन्फ़िगर कर सकते हैं MessageInterpolator, लेकिन Localeजब आप कॉल करते हैं तो निर्दिष्ट करने का कोई तरीका नहीं हैvalidate । इसलिए आप एक स्थैतिक ThreadLocal<Locale>(या बेहतर अभी तक, अन्य सामानों के साथ एक सामान्य कंटेनर बना सकते हैं ThreadLocalजो आपके लिए आवश्यक हो सकता है और फिर MessageInterpolatorउसी Localeसे आपका रिवाज हो सकता है। अगला चरण ServletFilterएक सत्र मान का उपयोग करना या request.getLocale()लोकेल को चुनना और स्टोर करना है। यह आपके ThreadLocalसंदर्भ में है।


4

जैसा कि @unknown (google) द्वारा उल्लेख किया गया था, यह उपयोग एक वैश्विक चर को परिभाषित करने के लिए है जिसमें संदर्भित प्रत्येक थ्रेड में अद्वितीय हो सकता है। यह usages आमतौर पर कुछ प्रकार की प्रासंगिक जानकारी संग्रहीत करता है जो निष्पादन के वर्तमान थ्रेड से जुड़ा हुआ है।

हम जावा ईई के प्रति जागरूक नहीं होने वाली कक्षाओं के लिए उपयोगकर्ता पहचान पास करने के लिए एक जावा ईई वातावरण में इसका उपयोग करते हैं (HttpSession, या EJB SessionContext तक पहुंच नहीं है)। इस तरह से कोड, जो सुरक्षा आधारित संचालन के लिए पहचान का उपयोग करता है, हर विधि कॉल में स्पष्ट रूप से इसे पारित किए बिना, कहीं से भी पहचान तक पहुंच सकता है।

अधिकांश जावा ईई कॉल में परिचालन का अनुरोध / प्रतिक्रिया चक्र इस प्रकार के उपयोग को आसान बनाता है क्योंकि यह थ्रेडलोक को सेट और अनसेट करने के लिए अच्छी तरह से परिभाषित प्रवेश और निकास बिंदु देता है।


4

थ्रेडलोक गैर-सिंक्रनाइज़ विधि में कई थ्रेड्स द्वारा उत्परिवर्तित ऑब्जेक्ट तक पहुंच सुनिश्चित करेगा, सिंक्रनाइज़ किया गया है, जिसका अर्थ है कि विधि के भीतर उत्परिवर्तनीय वस्तु को अपरिवर्तनीय बनाया जा सकता है।

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

परिभाषा से:

जावा में थ्रेडलोकल क्लास आपको वैरिएबल बनाने में सक्षम बनाता है जिसे केवल उसी थ्रेड द्वारा पढ़ा और लिखा जा सकता है। इस प्रकार, भले ही दो थ्रेड्स एक ही कोड को निष्पादित कर रहे हों, और कोड में थ्रेडलोक वैरिएबल का संदर्भ हो, तो दोनों थ्रेड एक दूसरे के थ्रेडलोक वैरिएबल को नहीं देख सकते हैं।

Threadजावा में प्रत्येक में होता ThreadLocalMapहै।
कहाँ पे

Key = One ThreadLocal object shared across threads.
value = Mutable object which has to be used synchronously, this will be instantiated for each thread.

थ्रेडलोक को प्राप्त करना:

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

यदि थ्रेडलोक के गेटर () को थ्रेडलोकैम्पैम्प के साथ कोई मान नहीं मिला Thread; तब यह इनिशियलव्यू () को धागे के संबंध में अपनी निजी कॉपी प्राप्त करने के लिए आमंत्रित करेगा।

class SimpleDateFormatInstancePerThread {

    private static final ThreadLocal<SimpleDateFormat> dateFormatHolder = new ThreadLocal<SimpleDateFormat>() {

        @Override
        protected SimpleDateFormat initialValue() {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd") {
                UUID id = UUID.randomUUID();
                @Override
                public String toString() {
                    return id.toString();
                };
            };
            System.out.println("Creating SimpleDateFormat instance " + dateFormat +" for Thread : " + Thread.currentThread().getName());
            return dateFormat;
        }
    };

    /*
     * Every time there is a call for DateFormat, ThreadLocal will return calling
     * Thread's copy of SimpleDateFormat
     */
    public static DateFormat getDateFormatter() {
        return dateFormatHolder.get();
    }

    public static void cleanup() {
        dateFormatHolder.remove();
    }
}

अब wrapper.getDateFormatter()कॉल करेंगे threadlocal.get()और उस की जाँच करेगा currentThread.threadLocalMapशामिल हैं इस (threadlocal) उदाहरण।
यदि हां इसी थ्रेडलोकल उदाहरण के लिए मान (SimpleDateFormat) लौटाएं
तो मानचित्र को इस थ्रेडलोक उदाहरण, initialValue () के साथ जोड़ें।

इस उत्परिवर्ती वर्ग पर हासिल की गई सुरक्षा के साथ-साथ थ्रेड की सुरक्षा; प्रत्येक थ्रेड द्वारा अपने स्वयं के परिवर्तनशील उदाहरण के साथ काम कर रहा है लेकिन उसी थ्रेडलोक उदाहरण के साथ। इसका मतलब है कि सभी थ्रेड कुंजी के रूप में एक ही थ्रेडलोक उदाहरण को साझा करेंगे, लेकिन मूल्य के रूप में अलग-अलग SimpleDateFormat उदाहरण।

https://github.com/skanagavelu/yt.tech/blob/master/src/ThreadLocalTest.java


3

थ्रेड-लोकल वैरिएबल का इस्तेमाल अक्सर म्यूटेबल सिंगलेट्स या ग्लोबल वैरिएबल्स के आधार पर डिजाइन में शेयरिंग को रोकने के लिए किया जाता है।

जब आप एक कनेक्शन पूल का उपयोग नहीं कर रहे हैं तो प्रत्येक थ्रेड के लिए अलग जेडडीबीसी कनेक्शन बनाने जैसे परिदृश्यों में इसका उपयोग किया जा सकता है।

private static ThreadLocal<Connection> connectionHolder
           = new ThreadLocal<Connection>() {
      public Connection initialValue() {
           return DriverManager.getConnection(DB_URL);
          }
     };

public static Connection getConnection() {
      return connectionHolder.get();
} 

जब आप getConnection कहते हैं, तो यह उस थ्रेड से जुड़ा एक कनेक्शन लौटा देगा। इसे अन्य संपत्तियों जैसे डेटफॉर्म, ट्रांजैक्शन के संदर्भ में भी किया जा सकता है जिन्हें आप थ्रेड के बीच साझा नहीं करना चाहते हैं।

आप उसी के लिए स्थानीय चर का उपयोग भी कर सकते थे, लेकिन ये संसाधन आमतौर पर निर्माण में समय लेते हैं, इसलिए जब भी आप उनके साथ कुछ व्यावसायिक तर्क करते हैं तो आप उन्हें बार-बार नहीं बनाना चाहते हैं। हालाँकि, थ्रेडलोक मान थ्रेड ऑब्जेक्ट में ही संग्रहीत होते हैं और जैसे ही थ्रेड कचरा एकत्र किया जाता है, ये मान भी चले गए हैं।

यह लिंक बहुत अच्छी तरह से ThreadLocal के उपयोग बताते हैं।


2
इस उदाहरण में एक प्रमुख मुद्दा है: कनेक्शन बंद करने के लिए कौन जिम्मेदार है? इस कनेक्शन को इनिशियल वैल्यू के रूप में बनाने के बजाय, कनेक्शन के उपभोक्ता को कनेक्शन स्पष्ट रूप से बनाने दें और थ्रेडलोक के माध्यम से इसे धागे से बांधें। कनेक्शन का निर्माता फिर समापन के लिए भी जिम्मेदार है। यह इस उदाहरण में स्पष्ट नहीं है। कनेक्शन बनाना और बांधना भी Transaction.begin () और Transaction.end () जैसी किसी चीज़ द्वारा एक साधारण ढांचे में छिपाया जा सकता है।
रिक-रेनर लुडविग

2

ThreadLocal जावा में वर्ग आप चर है कि केवल पढ़ सकते हैं और एक ही धागे से लिखा जा सकता है बनाने के लिए सक्षम बनाता है। इस प्रकार, भले ही दो थ्रेड्स एक ही कोड को निष्पादित कर रहे हों, और कोड में थ्रेडलोक वैरिएबल का संदर्भ हो, तो दोनों थ्रेड एक दूसरे के थ्रेडलोक वैरिएबल को नहीं देख सकते हैं।

अधिक पढ़ें


2

वहाँ एक प्रयोग करने के लिए 3 परिदृश्य दिए गए हैं वर्ग सहायक multithread कोड में SimpleDateFormat, जो सबसे अच्छा एक प्रयोग है जैसे ThreadLocal

परिदृश्य

1- लॉक या सिंक्रोनाइज़ेशन मैकेनिज़्म की मदद से शेयर ऑब्जेक्ट की तरह इस्तेमाल करना जिससे ऐप धीमा हो जाता है

2- एक विधि के अंदर एक स्थानीय वस्तु के रूप में उपयोग करना

इस परिदृश्य में, यदि हमारे पास 4 थ्रेड हैं, तो हर एक में 1000 बार कॉल करने की विधि है, तो हमारे पास
4000 SimpleDateFormat ऑब्जेक्ट बनाए गए हैं और GC द्वारा उन्हें मिटाने की प्रतीक्षा कर रहे हैं

3- थ्रेडलोक का उपयोग करना

अगर हमारे पास 4 धागे हैं और हमने प्रत्येक धागे को एक SimpleDateFormat उदाहरण दिया है,
तो हमारे पास 4 धागे हैं , SimpleDateFormat के 4 ऑब्जेक्ट

ताला तंत्र और वस्तु निर्माण और विनाश की कोई आवश्यकता नहीं है। (अच्छा समय जटिलता और अंतरिक्ष जटिलता)


2

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


1

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


1

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

import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;


public class ThreadId {
private static final AtomicInteger nextId = new AtomicInteger(1000);

// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId = ThreadLocal.withInitial(() -> nextId.getAndIncrement());


// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
    return threadId.get();
}

public static void main(String[] args) {

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

}
}

1

Threadlocal शून्य लागत के साथ वस्तुओं पुनर्प्रयोग प्राप्त करने के लिए एक बहुत ही आसान तरीका प्रदान करता है।

मेरे पास एक स्थिति थी जहां प्रत्येक अद्यतन अधिसूचना पर कई थ्रेड्स परस्पर कैश की छवि बना रहे थे।

मैंने प्रत्येक थ्रेड पर थ्रेडलोक का उपयोग किया है, और फिर प्रत्येक थ्रेड को पुरानी छवि को रीसेट करने की आवश्यकता है और फिर इसे अपने अद्यतन अधिसूचना पर कैश से फिर से अपडेट करें।

ऑब्जेक्ट पूल से सामान्य पुन: प्रयोज्य वस्तुओं में उनके साथ धागा सुरक्षा लागत जुड़ी होती है, जबकि इस दृष्टिकोण में कोई नहीं होता है।


0

थ्रेडलोकल वैरिएबल के लिए एक महसूस करने के लिए इस छोटे से उदाहरण की कोशिश करें:

public class Book implements Runnable {
    private static final ThreadLocal<List<String>> WORDS = ThreadLocal.withInitial(ArrayList::new);

    private final String bookName; // It is also the thread's name
    private final List<String> words;


    public Book(String bookName, List<String> words) {
        this.bookName = bookName;
        this.words = Collections.unmodifiableList(words);
    }

    public void run() {
        WORDS.get().addAll(words);
        System.out.printf("Result %s: '%s'.%n", bookName, String.join(", ", WORDS.get()));
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new Book("BookA", Arrays.asList("wordA1", "wordA2", "wordA3")));
        Thread t2 = new Thread(new Book("BookB", Arrays.asList("wordB1", "wordB2")));
        t1.start();
        t2.start();
    }
}


कंसोल आउटपुट, यदि थ्रेड बुकए पहले किया जाता है:
परिणाम बुक ए: 'वर्डए 1, वर्डए 2, वर्डए 3'।
परिणाम BookB: 'wordB1, wordB2'।

कंसोल आउटपुट, यदि थ्रेड बुकबी पहले किया जाता है:
परिणाम बुकबी: 'वर्डबी 1, वर्डबी 2'।
परिणाम BookA: 'wordA1, wordA2, wordA3'।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.