2012-01-11 6 views
11

सब!java.util.concurrent में अजीब कोड। लिंक्डब्लॉकिंग क्यूयू

मैं LinkedBlockingQueue में अजीब कोड मिला:

private E dequeue() { 
     // assert takeLock.isHeldByCurrentThread(); 
     Node<E> h = head; 
     Node<E> first = h.next; 
     h.next = h; // help GC 
     head = first; 
     E x = first.item; 
     first.item = null; 
     return x; 
} 

कौन समझा सकता है इसलिए हम स्थानीय चर ज की जरूरत है? यह जीसी के लिए कैसे मदद कर सकता है?

+0

शायद टिप्पणी पुरानी है (आप संस्करण नियंत्रण ढूंढकर टिप्पणी को ट्रैक करने के लिए कर सकते हैं?) :) – milan

+2

यह दिलचस्प है कि इस अस्थायी वर और टिप्पणी केवल में जोड़ा गया जावा 7. तो यह कुछ इरादे से निश्चित रूप से था। Http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/LinkedBlockingQueue.java#LinkedBlockingQueue.extract%28%29 और http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/util/concurrent/LinkedBlockingQueue.java#LinkedBlockingQueue.dequeue%28%29 – Vadzim

+0

जो ओपनजेडके है, ओरेकल के लिंकडब्लॉकिंग क्यूयू मैक पर jdk 6 (1.6.0_29-b11-402.jdk) में temp चर है। – milan

उत्तर

1

बेहतर समझने के लिए कि क्या होता है देखते हैं कि कोड को निष्पादित करने के बाद सूची कैसी दिखती है।

1 -> 2 -> 3 
फिर h अंक head को

और firsth.next करने के लिए:: सबसे पहले एक प्रारंभिक सूची पर विचार

1 -> 2 -> 3 
| | 
h first 

फिर h को h.next अंक और first को head अंक:

1 -> 2 -> 3 
| /\ 
h head first 

अब, व्यावहारिक रूप से हम जानते हैं कि वें ere केवल पहले तत्व को इंगित करने वाला सक्रिय संदर्भ है, जो स्वयं (h.next = h) है, और हम यह भी जानते हैं कि जीसी उन वस्तुओं को एकत्र करता है जिनके पास कोई सक्रिय संदर्भ नहीं है, इसलिए जब विधि समाप्त होती है, तो सूची के पुराने (पुराने) सिर जीसी द्वारा सुरक्षित रूप से एकत्र किया जाना चाहिए क्योंकि h केवल विधि के दायरे में मौजूद है।

यह कहा है, यह बताया गया है, और मैं इस बात से सहमत है कि यहां तक ​​कि क्लासिक विपंक्ति विधि के साथ (यानी सिर्फ first बिंदु head.next को बनाने के लिए और head बिंदु first करने के लिए) वहाँ कोई और अधिक पुराने सिर की ओर इशारा संदर्भ हैं । हालांकि, इस परिदृश्य में, पुराना सिर स्मृति में लटक रहा है और अभी भी next क्षेत्र first की ओर इशारा करते हुए फ़ील्ड है, जबकि आपके द्वारा पोस्ट किए गए कोड में, केवल एक चीज शेष एक अलग वस्तु है जो स्वयं को इंगित करती है। यह तेजी से कार्य करने के लिए जीसी को ट्रिगर कर सकता है।

+0

डाउनवॉटिंग कारण एच के पास 'h.next = h' के बिना भी कोई संदर्भ नहीं होगा। – Vadzim

+1

@ वाडज़िम: मैं यह नहीं कह रहा था कि, मैं सिर्फ यह बता रहा था कि उसने जो कोड पोस्ट किया था, वह क्या होता है। – Tudor

+0

सवाल इस बारे में नहीं है। यह क्यों है 'सिर्फ = head = head.next' क्यों नहीं। लेकिन वैसे भी ग्राफिक्स के लिए धन्यवाद। ध्यान दें कि सिर में हमेशा पहले आइटम नहीं होते हैं। – Vadzim

0

यहां एक कोड नमूना है जो प्रश्न को दर्शाता है: http://pastebin.com/zTsLpUpqrunWith() के बाद एक जीसी निष्पादित करना और दोनों संस्करणों के लिए एक ढेर डंप लेना कहता है कि केवल एक आइटम उदाहरण है।

+0

तो जीसी के लिए "सहायता" क्या है? – Vadzim

+0

शायद कुछ परिदृश्यों में, मुझे नहीं पता, शायद हम उस व्यक्ति को ढूंढ सकें जिसने टिप्पणी लिखी है :) – milan

4

शायद थोड़ा देर हो चुकी है, लेकिन वर्तमान स्पष्टीकरण मेरे लिए पूरी तरह असंतोषजनक है और मुझे लगता है कि मुझे एक और समझदार स्पष्टीकरण मिला है।

सभी जावा जीसी पहले रूट रूट से किसी तरह का ट्रेसिंग करता है। इसका मतलब है कि यदि पुराना सिर एकत्र किया जाता है तो हम next वैरिएबल को किसी भी तरह से नहीं पढ़ेंगे - ऐसा करने का कोई कारण नहीं है। इसलिए IF अगले पुनरावृत्ति में सिर एकत्र किया जाता है इससे कोई फर्क नहीं पड़ता।

उपर्युक्त वाक्य में आईएफ यहां महत्वपूर्ण हिस्सा है। कुछ अलग के बगल में सेटिंग के बीच का अंतर सिर एकत्र करने के लिए कोई फर्क नहीं पड़ता है, लेकिन अन्य वस्तुओं के लिए एक अंतर बना सकता है।

चलो एक साधारण पीढ़ी जीसी मानते हैं: यदि सिर युवा सेट में है, तो इसे अगले जीसी में किसी भी तरह से एकत्र किया जाएगा। लेकिन अगर यह पुराने सेट में है तो यह केवल तभी एकत्र किया जाएगा जब हम एक पूर्ण जीसी करते हैं जो शायद ही कभी होता है।

तो क्या होता है यदि सिर पुराने सेट में है और हम एक युवा जीसी करते हैं?इस मामले में जेवीएम मानता है कि पुराने ढेर में हर वस्तु अभी भी जिंदा है और युवा जीसी के लिए रूट सेट में पुराने से युवा वस्तुओं से प्रत्येक संदर्भ जोड़ती है। और यही वही है जो असाइनमेंट से बचाता है: पुरानी ढेर में लिखना आमतौर पर एक लिखने की बाधा या कुछ के साथ संरक्षित होता है ताकि JVM ऐसे असाइनमेंट को पकड़ सके और उन्हें सही तरीके से संभाल सके - हमारे मामले में यह ऑब्जेक्ट next रूट सेट से इंगित करता है जिसके परिणाम हैं।

लघु उदाहरण:

मान लें हम 1 (old) -> 2 (young) -> 3 (xx) है। अगर हम अपनी सूची से अब 1 और 2 हटा देते हैं, तो हम उम्मीद कर सकते हैं कि दोनों तत्व अगले जीसी द्वारा एकत्र किए जाएंगे। लेकिन अगर केवल एक युवा जीसी होता है और हमने पुराने में next पॉइंटर को नहीं हटाया है, तो तत्व 1 और 2 एकत्र नहीं किए जाएंगे। इसके विपरीत हम 1 में सूचक को हटा दिया है, तो, 2 जवान जीसी द्वारा एकत्र की जाएगी ..

+0

मुझे वास्तव में आप क्या कह रहे हैं और मैंने जो कहा है उसके बीच कोई अंतर नहीं दिखता है। मैंने यह भी कहा है कि अगले को हटाने से जीसी तेजी से सिर इकट्ठा कर सकता है। – Tudor

+1

@ ट्यूडर वेल मैंने समझाया कि कौन सी तंत्र व्यवहार में बदलाव का कारण बनती है और किस परिस्थिति में यह घटित होता है, जो निश्चित रूप से मेरे लिए कुछ और अधिक महत्वपूर्ण लगता है "जीसी अलग-अलग कार्य कर सकता है"। इसके अलावा यह पहले भी एकत्रित होने के बारे में नहीं है (जैसा कि यह स्पष्ट रूप से बकवास है), लेकिन बाद के तत्वों के बारे में - वे अलग-अलग वस्तुएं हैं। – Voo

+0

मैंने अपनी टिप्पणी में कहा है कि वास्तविक कार्यान्वयन की अनुपस्थिति में, मैं केवल यह अनुमान लगा सकता हूं कि वह असाइनमेंट क्या करना है। दूसरी तरफ, आपने वास्तव में बिना किसी स्रोत और उपयोग किए जाने वाले शब्दों "युवा जीसी" के बिना वास्तव में उन्हें पेश किए बिना कुछ पूर्ण बयान दिए हैं। – Tudor

6

आप jsr166 src को देखो तो आप हमलावर प्रतिबद्ध

http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/LinkedBlockingQueue.java?view=log (v 1.51 देख पाएंगे)

इससे पता चलता है इस सवाल का जवाब इस बग रिपोर्ट

http://bugs.sun.com/view_bug.do?bug_id=6805775

पूरी चर्चा इस सूत्र में है

http://thread.gmane.org/gmane.comp.java.jsr.166-concurrency/5758

"सहायता जीसी" बिट कार्यकाल में खून बहने से बचने के बारे में है।

चीयर्स

मैट

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