2012-03-02 6 views
11

एक जावा threaddump मैं निम्नलिखित पाया में:एकाधिक जावा धागे प्रतीत होता है कि एक ही मॉनिटर लॉकिंग?

"TP-Processor184" daemon prio=10 tid=0x00007f2a7c056800 nid=0x47e7 waiting for monitor entry [0x00007f2a21278000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at org.apache.jackrabbit.core.state.SharedItemStateManager.getNonVirtualItemState(SharedItemStateManager.java:1725) 
    - locked <0x0000000682f99d98> (a org.apache.jackrabbit.core.state.SharedItemStateManager) 
    at org.apache.jackrabbit.core.state.SharedItemStateManager.getItemState(SharedItemStateManager.java:257) 

"TP-Processor137" daemon prio=10 tid=0x00007f2a7c00f800 nid=0x4131 waiting for monitor entry [0x00007f2a1ace7000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at org.apache.jackrabbit.core.state.SharedItemStateManager.getNonVirtualItemState(SharedItemStateManager.java:1725) 
    - locked <0x0000000682f99d98> (a org.apache.jackrabbit.core.state.SharedItemStateManager) 
    at org.apache.jackrabbit.core.state.SharedItemStateManager.getItemState(SharedItemStateManager.java:257) 

यहां मुद्दा यह जा रहा है कि दोनों धागे की निगरानी < 0x0000000682f99d98> लॉक कर दिया है (उनमें से भले ही अब दो अलग अलग अन्य पर नज़र रखता है के लिए इंतज़ार कर)।

थ्रेड डंप विश्लेषक को देखते समय, उस मॉनिटर के चयन के साथ, यह वास्तव में "थ्रेड लॉक मॉनिटर: 2" नीचे, और "2 थ्रेड लॉकिंग" कहता है। स्क्रीनशॉट के लिए कृपया https://lh4.googleusercontent.com/-fCmlnohVqE0/T1D5lcPerZI/AAAAAAAAD2c/vAHcDiGOoMo/s971/locked_by_two_threads_3.png देखें, मुझे यहां छवियों को पेस्ट करने की अनुमति नहीं है।

क्या इसका मतलब है कि थ्रेडडंप मॉनीटर लॉक जानकारी के संबंध में परमाणु नहीं हैं? मैं कल्पना नहीं कर सकता कि यह वास्तव में JVM (1.6.0_26-b03) की लॉकिंग बग है।

Can several threads hold a lock on the same monitor in Java? में एक समान प्रश्न पूछा जा चुका है, लेकिन मेरे जवाब में एक ही मॉनीटर को लॉक करने वाले कई धागे के वास्तविक बिंदु को नहीं देखा गया, भले ही वे किसी अन्य के लिए इंतजार कर रहे हों।

अद्यतन मई 13 वीं 2014:

नया सवाल Multiple threads hold the same lock? व्यवहार पुन: पेश करने कोड है, और @rsxg उसके जवाब की तर्ज यहाँ के साथ एक बग रिपोर्ट अनुसार https://bugs.openjdk.java.net/browse/JDK-8036823 दायर किया है।

+0

मेरे उत्तर दोस्त पर कोई प्रतिक्रिया? मैंने इसे इंगित करने के लिए संपादित किया कि कोड के बाद के संस्करणों में लाइन 1725 पर 'प्रतीक्षा() 'है। कृपया स्वीकार करें कि यह सही है या नहीं। – Gray

+0

हम जैकबैबिट संस्करण 1.6.5 का उपयोग कर रहे हैं। मेरे एक दोस्त ने यह भी देखा कि संस्करण 2.3.6 में एक ही पंक्ति संख्या पर 'प्रतीक्षा करें), क्योंकि यह आश्चर्यजनक रूप से मेल खाता है, लेकिन दुर्भाग्य से यह गलत स्रोत कोड है ... – jfrantzius

उत्तर

2

आप भारी संकुचित ताले का विश्लेषण करते समय JVM में स्टैक ट्रेस रूटीन में कॉस्मेटिक बग में भाग रहे हैं - यह this bug जैसा ही हो सकता है या नहीं भी हो सकता है।

तथ्य यह है कि आपके दो धागे में से कोई भी वास्तव में SharedItemStateManager पर लॉक प्राप्त करने में कामयाब रहा है, क्योंकि आप इस तथ्य से देख सकते हैं कि वे waiting for monitor entry की रिपोर्ट कर रहे हैं। बग यह है कि दोनों मामलों में स्टैक ट्रेस में आगे बढ़ने के लिए उन्हें locked के बजाय waiting to lock की रिपोर्ट करनी चाहिए।

इस तरह अजीब स्टैक निशान का विश्लेषण करते समय कामकाज हमेशा यह जांचना है कि locked होने का दावा करने वाला एक थ्रेड एक ऑब्जेक्ट पर एक लॉक प्राप्त करने का भी इंतजार नहीं कर रहा है।

(पार संदर्भित के रूप में this Oracle document, प्रति स्रोत के साथ स्टैक ट्रेस में लाइन नंबर, कोड के बाद से वहाँ waiting for monitor entry शीर्षक में आंकड़े के बीच कोई रिश्ता और स्टैक ट्रेस में locked रेखा है। दुर्भाग्य से इस विश्लेषण की आवश्यकता है 0x00007f2a21278000 लाइन TP-Processor184" daemon prio=10 tid=0x00007f2a7c056800 nid=0x47e7 waiting for monitor entry [0x00007f2a21278000]को धागे के लिए वैध स्टैक क्षेत्र का अनुमान है। तो यह एक मॉनिटर आईडी की तरह दिखता है लेकिन यह नहीं है - और आप देख सकते हैं कि आपके द्वारा दिए गए दो थ्रेड अलग-अलग पते पर हैं ढेर)।

+0

स्टैक ट्रेस रूटीन में एक कॉस्मेटिक बग समझदार लगता है , और मॉनीटर के अनन्य नहीं होने के कारण मैं इसके बारे में बहुत बेहतर महसूस करूंगा :) अपने कामकाज के बारे में (यह तय करने के लिए कि) क्या हो रहा है, दोनों धागे ने उसी ऑब्जेक्ट को लॉक नहीं किया ('<0x0000000682f99d98>') एक लॉक प्राप्त करने की प्रतीक्षा ('[0x00007f2a21278000]')? – jfrantzius

+0

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

+0

@jfrantzius ओरेकल ने थ्रेड डंप हेडर में विभिन्न फ़ील्ड के अर्थ को स्पष्ट करने के लिए प्रलेखन जारी किया है, मैंने अपना जवाब अपडेट किया है। – rxg

2

जब कोई थ्रेड किसी ऑब्जेक्ट को लॉक करता है लेकिन प्रतीक्षा करें() का कोई अन्य थ्रेड उसी ऑब्जेक्ट को लॉक कर सकता है। आपको सभी प्रतीक्षाों को उसी लॉक को "होल्डिंग" करने में सक्षम होना चाहिए।

AFAIK, एकमात्र अन्य अवसर तब होता है जब एकाधिक धागे बंद हो जाते हैं और प्रतीक्षा करते हैं और लॉक को पुनः प्राप्त करने के लिए तैयार होते हैं। एक अधिसूचना पर सभी()। वे अब और इंतजार नहीं कर रहे हैं, लेकिन जब तक वे लॉक प्राप्त नहीं कर लेते तब तक जारी नहीं रह सकते हैं। (एक समय में केवल एक धागा यह कर सकता है)

+0

बस @ पीटर को स्पष्ट करने के लिए, आपका मतलब है: " जब कोई थ्रेड किसी ऑब्जेक्ट को लॉक करता है लेकिन प्रतीक्षा करें() s _on_that_same_object_ कोई अन्य थ्रेड ..." – Gray

+0

@ पीटर: बिल्कुल, और थ्रेड * एक ही ऑब्जेक्ट पर प्रतीक्षा नहीं कर रहे हैं, लेकिन दो अलग-अलग लोगों पर (यदि उन हेक्साडेसिमल संख्या का मतलब वस्तुओं के स्मृति पते हैं, तो है ...) – jfrantzius

+0

ठीक है, वे अभी भी प्रतीक्षा नहीं कर रहे हैं() एक ही ऑब्जेक्ट पर आईएनजी, लेकिन वे * कुछ * (शायद जीसी) की प्रतीक्षा कर रहे हैं ... वैसे भी, उन्होंने प्रतीक्षा() को कॉल करके लॉक जारी नहीं किया है, लेकिन ऐसा लगता है कि दोनों ने "सिंक्रनाइज़ (यह) "एक ही ऑब्जेक्ट के लिए" यह " – jfrantzius

3

मुझे नहीं लगता कि आपका धागा डंप कह रहा है कि आपके दो धागे "दो अलग-अलग मॉनीटरों की प्रतीक्षा कर रहे हैं"। मुझे लगता है कि यह कह रहा है कि वे दोनों एक ही मॉनिटर पर इंतजार कर रहे हैं लेकिन दो अलग-अलग कोड बिंदुओं पर हैं। यह एक स्टैक स्थान या ऑब्जेक्ट इंस्टेंस स्थान या कुछ हो सकता है। यह analyzing the stack dumps के बारे में एक महान दस्तावेज़ है।

क्या कई धागे जावा में एक ही मॉनीटर पर लॉक रख सकते हैं?

नहीं। आपका स्टैक डंप एक ही कोड पर उसी मॉनिटर पर लॉक दो थ्रेड दिखा रहा है, लेकिन अलग-अलग स्टैक फ्रेम में - या जो भी मान ओएस निर्भर करता है।

संपादित करें:

मैं क्यों धागा डंप कह जा सकता है कि दोनों धागे एक लाइन बंद कर दिया के बाद से है कि अगर वे एक wait() विधि में हैं ही अनुमति दी जा रहा है है लगता है यकीन नहीं है। मैंने देखा है कि आप संस्करण 1.6.5 से लिंक कर रहे हैं। क्या वास्तव में वह संस्करण है जिसका आप उपयोग कर रहे हैं? संस्करण 2.3.6 (जो नवीनतम हो सकता है) में, 1725 line वास्तव में wait है।

1722  synchronized (this) { 
1723   while (currentlyLoading.contains(id)) { 
1724    try { 
1725     wait(); 
1726    } catch (InterruptedException e) { 

तुम भी स्टैक ट्रेस की इस तरह देख सकते हैं, भले ही यह एक विशेष synchronized ताला था। उदाहरण के लिए, लिनक्स के नीचे निम्न स्टैक डंप एक ही ऑब्जेक्ट पर उसी कोड पर लॉक दो धागे के लिए है, लेकिन Runnable.run() विधि के दो अलग-अलग उदाहरणों में है। यहां मेरा stupid little test program है। ध्यान दें कि मॉनीटर एंट्री नंबर अलग हैं, यहां तक ​​कि सोचा कि यह एक ही लॉक और एक ही कोड लाइन नंबर है।

"Thread-1" prio=10 tid=0x00002aab34055c00 nid=0x4874 
    waiting for monitor entry [0x0000000041017000..0x0000000041017d90] 
java.lang.Thread.State: BLOCKED (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <0x00002aab072a1318> (a java.lang.Object) 
    at com.mprew.be.service.auto.freecause.Foo$OurRunnable.run(Foo.java:38) 
    - locked <0x00002aab072a1318> (a java.lang.Object) 
    at java.lang.Thread.run(Thread.java:619) 

"Thread-0" prio=10 tid=0x00002aab34054c00 nid=0x4873 
    waiting for monitor entry [0x0000000040f16000..0x0000000040f16d10] 
java.lang.Thread.State: BLOCKED (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <0x00002aab072a1318> (a java.lang.Object) 
    at com.mprew.be.service.auto.freecause.Foo$OurRunnable.run(Foo.java:38) 
    - locked <0x00002aab072a1318> (a java.lang.Object) 
    at java.lang.Thread.run(Thread.java:619) 

पर मेरी मैक, प्रारूप अलग लेकिन फिर "प्रवेश की निगरानी" के बाद नंबर एक ही पंक्ति संख्या के लिए एक ही नहीं है।

"Thread-2" prio=5 tid=7f8b9c00d000 nid=0x109622000 
    waiting for monitor entry [109621000] 
java.lang.Thread.State: BLOCKED (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <7f3192fb0> (a java.lang.Object) 
    at com.mprew.be.service.auto.freecause.Foo$OurRunnable.run(Foo.java:38) 
    - locked <7f3192fb0> (a java.lang.Object) 

"Thread-1" prio=5 tid=7f8b9f80d800 nid=0x10951f000 
    waiting for monitor entry [10951e000] 
java.lang.Thread.State: BLOCKED (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <7f3192fb0> (a java.lang.Object) 
    at com.mprew.be.service.auto.freecause.Foo$OurRunnable.run(Foo.java:38) 
    - locked <7f3192fb0> (a java.lang.Object) 

This Oracle document निम्नलिखित के रूप में है कि मूल्य का वर्णन:

पता रेंज है, जो धागा

+0

दिलचस्प चीजें! मैं हमेशा मानता हूं कि मॉनीटर के लिए संख्या लॉक ऑब्जेक्ट्स के पते थे, लेकिन स्पष्ट रूप से नहीं। शायद यह * जेवीएम स्रोत कोड में खोदना मुश्किल नहीं होगा उस स्थान को खोजने के लिए जहां इन निशानों का निर्माण किया गया है, और देखें कि ये संख्याएं कहां से आती हैं। मुझे कबूल करना है कि मुझे यह मिनट सही नहीं लगता है, हालांकि –

+0

डंप में दो धागे इंतजार कर रहे हैं() एक ही वस्तु के लिए आईएनजी कि वे पहले बंद कर दिया था, हालांकि, वे दोनों वास्तव में ताला जारी किया है। यह एक उदाहरण है कि एक ही मॉनीटर के लिए दो अलग-अलग धागे के लिए थ्रेडडम्प में दो "लॉक" घटनाओं को कैसे दिखाया जा सकता है, लेकिन फिर भी मेरे थ्रेड डंप से अलग है। धागे वहां इंतजार नहीं करते हैं() और ताले (उसी मॉनिटर पर) को रिलीज़ नहीं किया है, दोनों ने प्राप्त किया है, और यह जेवीएम स्पेक के खिलाफ है। आप "मॉनिटर एंट्री" पते की मेरी गलत व्याख्या के बारे में सही हैं, केवल सूर्य को पता है कि इसका क्या अर्थ है ... – jfrantzius

+0

@ टॉम एंडरसन हाँ मुझे सही न तो, शायद कल ;-) – jfrantzius

0
"http-0.0.0.0-8080-96" daemon prio=10 tid=0x00002abc000a8800 nid=0x3bc4 waiting for monitor entry [0x0000000050823000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at org.apache.lucene.search.FieldCacheImpl$Cache.get(FieldCacheImpl.java:195) 
    - locked <0x00002aadae12c048> (a java.util.WeakHashMap) 

"http-0.0.0.0-8080-289" daemon prio=10 tid=0x00002abc00376800 nid=0x2688 waiting for monitor entry [0x000000005c8e3000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
    at org.apache.lucene.search.FieldCacheImpl$Cache.get(FieldCacheImpl.java:195) 
    - locked <0x00002aadae12c048> (a java.util.WeakHashMap 

"http-0.0.0.0-8080-295" daemon prio=10 tid=0x00002abc00382800 nid=0x268e runnable [0x000000005cee9000] 
    java.lang.Thread.State: RUNNABLE 
    at org.apache.lucene.search.FieldCacheImpl$Cache.get(FieldCacheImpl.java:195) 
    - locked <0x00002aadae12c048> (a java.util.WeakHashMap) 

हमारे धागा डंप में के लिए मान्य ढेर क्षेत्र के एक अनुमान देता है, हमारे पास कई थ्रेड लॉक समान मॉनीटर हैं, लेकिन केवल एक थ्रेड रननेबल है। शायद यह लॉक प्रतियोगिता की वजह से, हमारे पास 284 अन्य थ्रेड लॉक के लिए प्रतीक्षा कर रहे हैं। Multiple threads hold the same lock? ने कहा कि यह केवल थ्रेड डंप में मौजूद है, क्योंकि थ्रेड डंप परमाणु ऑपरेशन नहीं है।

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