थ्रेडलोकल कैसे कार्यान्वित किया जाता है? क्या यह जावा में कार्यान्वित किया गया है (थ्रेडिड से ऑब्जेक्ट में कुछ समवर्ती मानचित्र का उपयोग करके), या क्या यह कुछ अधिक कुशलता से करने के लिए कुछ जेवीएम हुक का उपयोग करता है?जावा के थ्रेडलोकल हुड के तहत कैसे लागू किया गया है?
उत्तर
यहां सभी उत्तरों सही हैं, लेकिन थोड़ा निराशाजनक है क्योंकि वे कुछ हद तक चमकते हैं कि ThreadLocal
का कार्यान्वयन कितना चालाक है। मैं सिर्फ source code for ThreadLocal
देख रहा था और इसे लागू करने के तरीके से सुखद रूप से प्रभावित था।
अनुभवहीन कार्यान्वयन
अगर मैं एक ThreadLocal<T>
वर्ग एपीआई जावाडोक में वर्णित दी लागू करने के लिए कहा था, आप क्या करेंगे? प्रारंभिक कार्यान्वयन Thread.currentThread()
का उपयोग करके इसकी कुंजी के रूप में होगा। यह उचित रूप से अच्छी तरह से काम करेगा लेकिन कुछ नुकसान है।
- थ्रेड विवाद -
ConcurrentHashMap
एक बहुत चालाक वर्ग है, लेकिन यह अंततः अभी भी किसी भी तरह से इसके साथ mucking से अधिक थ्रेड को रोकने से निपटने के लिए है, और अगर अलग धागे इसे नियमित रूप से हिट हुई, वहाँ मंदी हो जाएगा। - थ्रेड समाप्त होने के बाद भी, थ्रेड और ऑब्जेक्ट दोनों के लिए एक सूचक को स्थायी रूप से रखता है और जीसीड किया जा सकता है।
जीसी के अनुकूल कार्यान्वयन
ठीक कोशिश फिर से, weak references का उपयोग करके कचरा संग्रहण मुद्दे के साथ सौदा कर सकते हैं। WeakReferences के साथ काम कर भ्रमित हो सकते हैं, लेकिन यह एक नक्शा इतना की तरह बनाया का उपयोग करने के लिए पर्याप्त होना चाहिए: (! और हम होना चाहिए)
Collections.synchronizedMap(new WeakHashMap<Thread, T>())
या अगर हम Guava उपयोग कर रहे हैं:
new MapMaker().weakKeys().makeMap()
यह का मतलब है कि एक बार थ्रेड पर कोई और नहीं हो रहा है (जिसका अर्थ है कि यह समाप्त हो गया है) कुंजी/मूल्य कचरा इकट्ठा किया जा सकता है, जो एक सुधार है, लेकिन अभी भी थ्रेड विवाद समस्या को संबोधित नहीं करता है, जिसका अर्थ है कि अब तक हमारे ThreadLocal
सब कुछ नहीं है एक वर्ग के अद्भुत। इसके अलावा, अगर किसी ने समाप्त होने के बाद Thread
ऑब्जेक्ट्स पर पकड़ने का निर्णय लिया है, तो वे कभी भी जीसीएड नहीं होंगे, और इसलिए न ही हमारी वस्तुएं होंगी, भले ही वे तकनीकी रूप से पहुंच योग्य नहीं हों।
चालाक कार्यान्वयन
हम मूल्यों के धागे की मैपिंग के रूप में ThreadLocal
बारे में सोच रहा है, लेकिन हो सकता है कि वास्तव में इसके बारे में सोचो के लिए सही रास्ता नहीं है। थ्रेड से प्रत्येक थ्रेडलोकल ऑब्जेक्ट में मानों के मैपिंग के रूप में सोचने के बजाय, क्या होगा यदि हमने थ्रेडलोकल ऑब्जेक्ट्स के मानचित्रण के रूप में प्रत्येक थ्रेड में मानों के बारे में सोचा था?यदि प्रत्येक थ्रेड मैपिंग स्टोर करता है, और थ्रेडलोकल केवल उस मैपिंग में एक अच्छा इंटरफ़ेस प्रदान करता है, तो हम पिछले कार्यान्वयन के सभी मुद्दों से बच सकते हैं।
कार्यान्वयन कुछ इस तरह दिखेगा:
// called for each thread, and updated by the ThreadLocal instance
new WeakHashMap<ThreadLocal,T>()
संगामिति यहाँ बारे में चिंता करने की कोई जरूरत नहीं है, क्योंकि केवल एक धागा कभी इस नक्शे तक पहुँचने की जाएगी।
जावा देवों का यहां हमारे ऊपर एक बड़ा लाभ है - वे सीधे थ्रेड क्लास विकसित कर सकते हैं और इसमें फ़ील्ड और ऑपरेशंस जोड़ सकते हैं, और यही वही है जो उन्होंने किया है।
java.lang.Thread
में निम्नलिखित लाइनों है:
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;
कौन सा रूप में टिप्पणी से पता चलता है वास्तव में सभी मूल्यों का एक पैकेज-निजी मानचित्रण इस Thread
के लिए ThreadLocal
वस्तुओं के द्वारा पता लगाया जा रहा है। ThreadLocalMap
का कार्यान्वयन WeakHashMap
नहीं है, लेकिन यह उसी मूल अनुबंध का पालन करता है, जिसमें कमजोर संदर्भ से इसकी चाबियां शामिल हैं।
ThreadLocal.get()
तो तरह कार्यान्वित किया जाता है:
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
और ThreadLocal.setInitialValue()
तो जैसे:
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
अनिवार्य रूप से, पकड़ करने के लिए इस थ्रेड में एक नक्शा का उपयोग सब हमारे ThreadLocal
वस्तुओं। इस तरह, हमें अन्य थ्रेड (ThreadLocal
में मूल्यों के बारे में चिंता करने की आवश्यकता नहीं है, सचमुच वर्तमान थ्रेड में केवल मूल्यों तक पहुंच सकते हैं) और इसलिए कोई सहमति नहीं है। इसके अलावा, Thread
एक बार हो जाने पर, इसका नक्शा स्वचालित रूप से जीसीएड होगा और सभी स्थानीय वस्तुओं को साफ कर दिया जाएगा। भले ही Thread
पर रखा गया हो, ThreadLocal
ऑब्जेक्ट कमजोर संदर्भ द्वारा आयोजित किए जाते हैं, और जैसे ही ThreadLocal
ऑब्जेक्ट दायरे से बाहर हो जाता है, इसे साफ़ किया जा सकता है।
जरूरत नहीं कहने के लिए, मैं नहीं बल्कि इस कार्यान्वयन से प्रभावित था, यह काफी सुंदर ढंग से बेशक कोर जावा का हिस्सा होने का फायदा उठाते हुए संगामिति मुद्दों (का एक बहुत चारों ओर हो जाता है, लेकिन उस के बाद से यह इस तरह के एक चालाक है क्षम्य उन्हें है कक्षा) और उन वस्तुओं तक तेज़ और थ्रेड-सुरक्षित पहुंच की अनुमति देता है जिन्हें एक समय में केवल एक थ्रेड द्वारा एक्सेस किया जाना चाहिए।
टीएल; डॉThreadLocal
का कार्यान्वयन बहुत अच्छा है, और आप पहली नज़र में सोचने से कहीं अधिक तेज/स्मार्ट हो सकते हैं।
यदि आपको यह उत्तर पसंद आया तो आप मेरी (कम विस्तृत) discussion of ThreadLocalRandom
की भी सराहना कर सकते हैं।
Thread
/ThreadLocal
कोड के टुकड़े Oracle/OpenJDK's implementation of Java 8 से लिया।
जावा में थ्रेडलोकल वेरिएबल Thread.currentThread() उदाहरण द्वारा आयोजित हैश मैप तक पहुंचकर काम करता है।
सही नहीं है यही कारण है कि (या कम से कम यह किसी भी अब नहीं है)। Thread.currentThread() Thread.class में एक देशी कॉल है। इसके अलावा थ्रेड में "थ्रेडलोकैलमैप" है जो हैश कोड का एकल-बाल्टी (सरणी) है। यह ऑब्जेक्ट मानचित्र इंटरफ़ेस का समर्थन नहीं करता है। – user924272
यह मूल रूप से मैंने जो कहा है। currentThread() एक थ्रेड इंस्टेंस देता है, जिसमें मानों के लिए थ्रेडलोकल्स का नक्शा होता है। –
यह एक मानचित्र नहीं है! – user924272
आपका मतलब java.lang.ThreadLocal
है। यह काफी सरल है, वास्तव में, यह सिर्फ Thread
ऑब्जेक्ट के अंदर संग्रहीत नाम-मूल्य जोड़े का मानचित्र है (Thread.threadLocals
फ़ील्ड देखें)। एपीआई उस कार्यान्वयन के विस्तार को छुपाता है, लेकिन यह सब कुछ कम है।
तो, यह कोई ताले या विवाद नहीं करता है, है ना? – ripper234
मैं नहीं देख सकता कि किसी की आवश्यकता क्यों होनी चाहिए, यह देखते हुए कि परिभाषा के अनुसार डेटा केवल एक धागे के लिए दृश्यमान होता है। – skaffman
सही, कोई सिंक्रनाइज़ेशन या थ्रेडलोकैप मैप के अंदर या लॉकिंग नहीं है, क्योंकि यह केवल इन-थ्रेड तक पहुंच गया है। – Cowan
मान लीजिए कि आप ThreadLocal
को लागू करने जा रहे हैं, तो आप इसे थ्रेड-विशिष्ट कैसे बनाते हैं? बेशक सबसे आसान तरीका थ्रेड क्लास में एक गैर स्थैतिक क्षेत्र बनाना है, चलो इसे threadLocals
पर कॉल करें। चूंकि प्रत्येक थ्रेड को थ्रेड इंस्टेंस द्वारा दर्शाया जाता है, इसलिए प्रत्येक थ्रेड में threadLocals
भी अलग होगा।
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap
यहाँ क्या है: और यह भी क्या जावा करता है? चूंकि आपके पास केवल threadLocals
धागे के लिए है, इसलिए यदि आप threadLocals
को अपने ThreadLocal
(कहें, थ्रेड लोकल को Integer
के रूप में परिभाषित करें) के रूप में लें, तो आपके पास केवल एक विशिष्ट थ्रेड के लिए एक ThreadLocal
होगा। यदि आप थ्रेड के लिए एकाधिक ThreadLocal
चर चाहते हैं तो क्या होगा? सबसे आसान तरीका threadLocals
HashMap
बनाने के लिए है, प्रत्येक प्रविष्टि का key
ThreadLocal
चर का नाम है, और प्रत्येक प्रविष्टि के value
ThreadLocal
चर का मान है। थोड़ा उलझन में? मान लें कि हमारे पास दो धागे हैं, t1
और t2
। वे Runnable
उदाहरण Thread
कन्स्ट्रक्टर के पैरामीटर के रूप में लेते हैं, और दोनों में tlA
और tlb
नामक चर हैं। यह वैसे ही है।
t1.tlA
+-----+-------+
| Key | Value |
+-----+-------+
| tlA | 0 |
| tlB | 1 |
+-----+-------+
t2.tlB
+-----+-------+
| Key | Value |
+-----+-------+
| tlA | 2 |
| tlB | 3 |
+-----+-------+
सूचना है कि मूल्यों मेरे द्वारा बने होते हैं।
अब यह सही लगता है। लेकिन ThreadLocal.ThreadLocalMap
क्या है? यह सिर्फ HashMap
का उपयोग क्यों नहीं किया? समस्या को हल करने के लिए, देखते हैं क्या होता है जब हम ThreadLocal
वर्ग के set(T value)
विधि के माध्यम से एक मूल्य निर्धारित करने की अनुमति:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
getMap(t)
बस t.threadLocals
देता है। क्योंकि t.threadLocals
null
को initilized था, इसलिए हम createMap(t, value)
पहले दर्ज करें:
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
यह वर्तमान ThreadLocal
उदाहरण और मूल्य का उपयोग कर एक नया ThreadLocalMap
उदाहरण बनाता है स्थापित किया जाना। चलो देखते हैं क्या ThreadLocalMap
है की तरह, यह ThreadLocal
वर्ग
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
...
/**
* Construct a new map initially containing (firstKey, firstValue).
* ThreadLocalMaps are constructed lazily, so we only create
* one when we have at least one entry to put in it.
*/
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
...
}
ThreadLocalMap
वर्ग के मुख्य भाग के तथ्य हिस्से में है Entry class
, जो WeakReference
फैली हुई है। यह सुनिश्चित करता है कि यदि वर्तमान धागा निकलता है, तो यह कचरा स्वचालित रूप से एकत्र किया जाएगा। यही कारण है कि यह HashMap
के बजाय ThreadLocalMap
का उपयोग करता है।यह Entry
वर्ग के पैरामीटर के रूप में वर्तमान ThreadLocal
और इसके मूल्य से गुजरता है, इसलिए जब हम मूल्य प्राप्त करना चाहते हैं, हम इसे table
, जो Entry
वर्ग का एक उदाहरण है से मिल सकता है:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
यह वह जगह है ,
वैचारिक आप एक Map<Thread,T>
कि धागे की विशिष्ट ग मान संग्रहीत कर लेता पकड़े के रूप में एक ThreadLocal<T>
के बारे में सोच सकते हैं कि यह कैसे वास्तव में है, हालांकि यह नहीं है: क्या पूरी तस्वीर में की तरह है कार्यान्वित किया।
धागे-विशिष्ट मूल्यों को थ्रेड ऑब्जेक्ट में ही संग्रहीत किया जाता है; जब धागा समाप्त हो जाता है, तो धागे-विशिष्ट मूल्यों को कचरा इकट्ठा किया जा सकता है।
संदर्भ: JCIP
संकल्पनात्मक रूप से, हां। लेकिन जैसा कि आप देखते हैं कि कार्यान्वयन के ऊपर अन्य उत्तर फॉर्म पूरी तरह अलग हैं। – Archit
- 1. हुड के तहत लागू Win32 इवेंट-संचालित प्रोग्रामिंग कैसा है?
- 2. हुड के तहत विरासत
- 3. जावा 6 enums के लिए मूल्य() लागू किया गया है?
- 4. रिलेशनल डेटाबेस कैसे हुड के तहत काम करते हैं?
- 5. हुड के तहत, जावास्क्रिप्ट ऑब्जेक्ट हैश टेबल हैं?
- 6. एचटीपीशन कैसे लागू किया गया है?
- 7. ** पायथन में कैसे लागू किया गया है?
- 8. जावा 7 में मल्टी-कैच लागू किया गया है?
- 9. जावा में कितना सुपर लागू किया गया है?
- 10. हुड के तहत ईएफ को समझना। बनाम शामिल हों
- 11. एंड्रॉइड द्वारा जावा 6 एपीआई कितना लागू किया गया है?
- 12. पाइथन के अंश कैसे हैं .limit_denominator लागू किया गया?
- 13. जावा ओएस के तहत जावा
- 14. क्या ट्रिडियन हॉटफिक्सेस लागू किया गया है?
- 15. ऑब्जेक्टडेटा स्रोत अपडेट पैरामीटर में हुड के तहत FormView EditTemplate अद्यतन मान कैसे करता है?
- 16. पायथन में 'है' कीवर्ड कैसे लागू किया गया है?
- 17. थ्रेडलोकल
- 18. LINQ और C# में हुड के तहत 'कीवर्ड/से चुनें/चुनें' कीवर्ड कैसे लगाया जाता है?
- 19. बैंकिंग लेनदेन "हुड के तहत" कैसे काम करता है - संभवतः विस्तार से
- 20. सी # 4 में मेमेंटो पैटर्न कैसे लागू किया गया है?
- 21. CCython में string.find कैसे लागू किया गया है?
- 22. कैसे "देखें गणना" सर्वोत्तम लागू किया गया है?
- 23. जेएमएल जावा में एनोटेशन के रूप में क्यों लागू नहीं किया गया है?
- 24. जीमेल कैसे हुड
- 25. सिग्नल कैसे करें "अभी तक लागू नहीं किया गया"?
- 26. Response.IsClient कवर के तहत काम कैसे कनेक्ट किया जाता है?
- 27. डेस्कटॉप क्लास को लिनक्स के तहत कैसे समर्थित किया जाए?
- 28. memchr() हुड के नीचे कैसे काम करता है?
- 29. लिनक्स के तहत जावा डिमन: विकल्प?
- 30. कॉलवर्ट हुड के नीचे कैसे काम करता है?
आपके उत्तर शानदार दिखते हैं लेकिन यह मेरे लिए अभी बहुत लंबा है। +1 और स्वीकार किया गया है, और मैं इसे बाद में पढ़ने के लिए अपने getpocket.com खाते में जोड़ रहा हूं। धन्यवाद! – ripper234
मुझे थ्रेडलोकल जैसी चीज चाहिए जो मुझे मूल्यों की पूरी सूची तक पहुंचने दे, मुझे map.values () की तरह। तो, मेरा निष्पक्ष कार्यान्वयन एक WeakHashMap <स्ट्रिंग, ऑब्जेक्ट> है जहां कुंजी Thread.currentThread() है getName()। यह थ्रेड के संदर्भ से बचाता है। अगर धागा दूर हो जाता है, तो कुछ भी थ्रेड का नाम नहीं रखता है (एक धारणा, मैं स्वीकार करता हूं) और मेरा मूल्य दूर हो जाएगा। – bmauter
मैं वास्तव में [हाल ही में उस प्रभाव के लिए एक प्रश्न का उत्तर दिया] (http://stackoverflow.com/a/15654081/113632)। एक 'WeakHashMap' कई समस्याओं का परिचय देता है, यह थ्रेडसेफ नहीं है, और यह मुख्य रूप से मुख्य वस्तुओं के उपयोग के लिए है जिसका उद्देश्य == ऑपरेटर का उपयोग करके ऑब्जेक्ट पहचान के लिए समान तरीके से परीक्षण करता है "- इसलिए वास्तव में 'थ्रेड' ऑब्जेक्ट का उपयोग एक कुंजी के रूप में करना बेहतर करें। मैं आपके उपयोग के मामले के ऊपर ऊपर वर्णित गुवा कमजोर मैप्स का उपयोग करने का सुझाव दूंगा। –
dimo414