2009-09-29 13 views
28

संभावित डुप्लिकेट: When and how should I use a Threadlocal variableThreadLocal का उद्देश्य?


दिया here राज्यों के रूप में ThreadLocal के प्रयोजन कि चर एक वस्तु ThreadLocal चर युक्त तक पहुँचने के लिए किसी भी धागा करने के लिए स्थानीय है। एक वर्ग के सदस्य के रूप में थ्रेडलोकल वैरिएबल होने और फिर इसे थ्रेड पर स्थानीय चर होने के बजाए इसे थ्रेड पर स्थानीय बनाने में क्या अंतर होता है?

उत्तर

71

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

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

doGet(HttpServletRequest req, HttpServletResponse resp) { 
    User user = getLoggedInUser(req); 
    doSomething() 
    doSomethingElse() 
    renderResponse(resp) 
} 

अब क्या होता है यदि doSomething() विधियों को उपयोगकर्ता ऑब्जेक्ट तक पहुंच की आवश्यकता होती है? आप उपयोगकर्ता को एक आवृत्ति या स्थिर चर नहीं बना सकते हैं क्योंकि प्रत्येक थ्रेड उसी उपयोगकर्ता ऑब्जेक्ट का उपयोग करेगा। आप एक पैरामीटर के रूप आसपास उपयोगकर्ता वस्तु गुजर सकता है, लेकिन यह जल्दी से हर विधि कॉल में गंदा हो जाता है और लीक उपयोगकर्ता वस्तुओं:

doGet(HttpServletRequest req, HttpServletResponse resp) { 
    User user = getLoggedInUser(req); 
    doSomething(user) 
    doSomethingElse(user) 
    renderResponse(resp,user) 
} 

एक और अधिक सुरुचिपूर्ण समाधान एक ThreadLocal

doGet(HttpServletRequest req, HttpServletResponse resp) { 
    User user = getLoggedInUser(req); 
    StaticClass.getThreadLocal().set(user) 
    try { 
    doSomething() 
    doSomethingElse() 
    renderResponse(resp) 
    } 
    finally { 
    StaticClass.getThreadLocal().remove() 
    } 
} 
में उपयोगकर्ता वस्तु डाल करने के लिए है

अब किसी भी कोड है कि किसी भी समय उपयोगकर्ता वस्तु की आवश्यकता है धागा स्थानीय से निकाल कर यह की पकड़ प्राप्त कर सकते हैं, उन परेशान अतिरिक्त पैरामीटर का सहारा लेना जरूरत के बिना:

User user = StaticClass.getThreadLocal().get() 

यदि आप इस दृष्टिकोण का उपयोग करते हैं तो अंत में ब्लॉक में ऑब्जेक्ट को फिर से निकालने के लिए सावधान रहें। अन्यथा उपयोगकर्ता ऑब्जेक्ट उन वातावरणों में घूम सकता है जो थ्रेड पूल (जैसे टोमकैट ऐप सर्वर) का उपयोग करते हैं।

संपादित करें: स्थिर वर्ग के लिए कोड

class StaticClass { 
    static private ThreadLocal threadLocal = new ThreadLocal<User>(); 

    static ThreadLocal<User> getThreadLocal() { 
    return threadLocal; 
    } 
} 
+1

यहां स्टेटिक क्लास क्या है? कक्षा जो थ्रेड फैली हुई है? – Ajay

+0

स्टेटिक क्लास थ्रेडलोकल ऑब्जेक्ट को पकड़ने का एक आसान तरीका है। मैं स्टेटिक क्लास के लिए कोड शामिल करने के लिए उदाहरण संपादित करूंगा। – leonm

+7

मैं नहीं कहूंगा कि यह हमेशा अधिक सुरुचिपूर्ण है, लेकिन यह अधिक उपयुक्त है –

7

एक थ्रेड ऑब्जेक्ट में आंतरिक डेटा सदस्य हो सकते हैं लेकिन ये किसी भी व्यक्ति के लिए सुलभ हैं जिनके पास थ्रेड ऑब्जेक्ट का संदर्भ है (या प्राप्त कर सकते हैं)। एक थ्रेडलोकल जानबूझकर केवल उस थ्रेड के साथ जुड़ा हुआ है जो इसे एक्सेस करता है। इसका फायदा यह है कि कोई सहमति नहीं है (थ्रेडलोकल के संदर्भ में)। किसी थ्रेड के आंतरिक डेटा सदस्य के पास समान साझा अवस्था के सभी समान सहमतिएं होती हैं।

मुझे किसी विशेष धागे के साथ परिणाम जोड़ने का विचार समझाएं।

public class MyLocal<T> { 
    private final Map<Thread, T> values = new HashMap<Thread, T>(); 

    public T get() { 
    return values.get(Thread.currentThread()); 
    } 

    public void set(T t) { 
    values.put(Thread.currentThread(), t); 
    } 
} 

अब है कि तुलना में यह करने के लिए अधिक है, लेकिन दिए गए मान के रूप में आप देख सकते हैं वर्तमान धागा से निर्धारित होता है: एक ThreadLocal का सार कुछ इस तरह है। यही कारण है कि यह स्थानीय प्रत्येक धागे के लिए है।

+0

जानबूझकर प्रत्येक धागे से जुड़े अर्थ है? धागा स्वयं एक वस्तु सही है? तो वास्तव में धागे से जुड़ा हुआ मतलब है थ्रेड ऑब्जेक्ट से जुड़ा हुआ है? – Ajay

+0

@ अजय: हाँ। थ्रेडलोकल उदाहरण थ्रेड ऑब्जेक्ट्स से जुड़े सेमी-प्राइवेट डेटा स्ट्रक्चर के माध्यम से थ्रेड ऑब्जेक्ट्स से जुड़े होते हैं; "पैकेज निजी" सदस्यों को देखें थ्रेड। थ्रेड लॉकल्स और थ्रेड। शेरटेबल थ्रेडलोकल्स –

+0

@ स्टीफन: तो थ्रेड क्लास के सदस्य होने की तुलना में थ्रेडलोकल होने में क्या अंतर होता है। – Ajay

1

थ्रेडलोकल्स का लाभ यह है कि वे सादे वेनिला थ्रेड ... या थ्रेड के किसी भी उप-वर्ग पर चलने वाली विधियों के उपयोग से उपयोग योग्य हैं।

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

5

ThreadLocal webapplications में बहुत उपयोगी है। सामान्य पैटर्न यह है कि किसी वेब अनुरोध (आमतौर पर एक सर्वलेट फ़िल्टर में) की प्रसंस्करण की शुरुआत में स्थिति थ्रेडलोकल चर में संग्रहीत होती है। चूंकि अनुरोध के लिए सभी प्रसंस्करण 1 धागे में किया जाता है क्योंकि अनुरोध में भाग लेने वाले सभी घटकों के पास इस चर का उपयोग होता है।

2

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

और भूलें मत भूलें, जावा एपीआई संरचनाएं हैं, जो थ्रेड सुरक्षित नहीं हैं, उदा। DateFormat। डेटफॉर्मैट का एक स्थिर उदाहरण सर्वर पक्ष पर काम नहीं करता है।

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

10

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

इस तरह के एक वर्ग के उदाहरण एक जावा धागे का प्रतिनिधित्व करते हैं और यह हेरफेर करने की अनुमति (जैसे इसमें बाधा डालते हैं), लेकिन अलग से है कि वे बस नियमित वस्तुओं रहे हैं, और इनके सदस्यों सभी धागे कि की पकड़ प्राप्त कर सकते हैं से पहुँचा जा सकता ऑब्जेक्ट का संदर्भ (जो not hard है)।

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

थ्रेडलोकल प्रति-थ्रेड डेटा रखने का एक सरल, लचीला तरीका है जो को अन्य थ्रेड द्वारा समवर्ती रूप से एक्सेस नहीं किया जा सकता है, बिना किसी प्रयास या डिज़ाइन समझौता किए।

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