2009-04-14 12 views
11

पहले, here's a sample:जावा में काम सिंक्रनाइज़ करता है कैसे

public class Deadlock { 
    static class Friend { 
     private final String name; 
     public Friend(String name) { 
      this.name = name; 
     } 
     public String getName() { 
      return this.name; 
     } 
     public synchronized void bow(Friend bower) { 
      System.out.format("%s: %s has bowed to me!%n", 
        this.name, bower.getName()); 
      bower.bowBack(this); 
     } 
     public synchronized void bowBack(Friend bower) { 
      System.out.format("%s: %s has bowed back to me!%n", 
        this.name, bower.getName()); 
     } 
    } 

    public static void main(String[] args) { 
     final Friend alphonse = new Friend("Alphonse"); 
     final Friend gaston = new Friend("Gaston"); 
     new Thread(new Runnable() { 
      public void run() { alphonse.bow(gaston); } 
     }).start(); 
     new Thread(new Runnable() { 
      public void run() { gaston.bow(alphonse); } 
     }).start(); 
    } 
} 

क्या मैं नहीं मिलता है कैसे रुकावट होती है। मुख्य कार्य दो थ्रेड शुरू करता है जो प्रत्येक अपने स्वयं के धनुष शुरू करते हैं।

'सिंक्रनाइज़' ब्लॉक वास्तव में क्या करता है? वही कार्य उसी वस्तु के लिए चल रहा है (जैसा कि मैंने मूल रूप से सोचा था)? एक ही कक्षा के सभी वस्तुओं के लिए एक ही समारोह? एक ही ऑब्जेक्ट के लिए सभी सिंक्रनाइज़ फ़ंक्शन? एक ही कक्षा की सभी वस्तुओं के लिए सभी सिंक्रनाइज़ किए गए कार्यों?

यहां मेरी सहायता करें।

उत्तर

22

जावा में, प्रत्येक Objectsynchronize पर थ्रेड की क्षमता प्रदान करता है, या उस पर लॉक करता है। जब कोई विधि सिंक्रनाइज़ होती है, तो विधि लॉक के रूप में अपने ऑब्जेक्ट उदाहरण का उपयोग करती है। आपके उदाहरण में, bow और bowBack दोनों विधियां synchronized दोनों हैं, और दोनों एक ही कक्षा Friend में हैं। इसका अर्थ यह है कि इन विधियों को निष्पादित करने वाला कोई भी थ्रेड Friend इंस्टेंस पर इसके लॉक के रूप में सिंक्रनाइज़ होगा।

किसी घटना के समय एक गतिरोध का कारण होगा की एक अनुक्रम है:

  1. पहले थ्रेड कॉल alphonse.bow(gaston), जो synchronizedalphonseFriend वस्तु पर है शुरू कर दिया। इसका मतलब है कि थ्रेड को इस ऑब्जेक्ट से लॉक प्राप्त करना होगा।
  2. दूसरे थ्रेड ने gaston.bow(alphonse) पर कॉल करना शुरू किया, जो synchronizedgastonFriend ऑब्जेक्ट पर है। इसका मतलब है कि थ्रेड को इस ऑब्जेक्ट से लॉक प्राप्त करना होगा।
  3. पहला धागा अब bowback पर कॉल करता है और रिलीज होने के लिए gaston पर लॉक की प्रतीक्षा करता है।
  4. दूसरा धागा अब bowback पर कॉल करता है और रिलीज होने के लिए alphonse पर लॉक की प्रतीक्षा करता है।

और अधिक विस्तार से घटनाओं के अनुक्रम दिखाने के लिए:

  1. main() मुख्य Therad में निष्पादित करने के लिए शुरू होता है, दो Friend उदाहरणों बनाने (यह थ्रेड # 1 कहते हैं)। अब तक सब ठीक है.
  2. मुख्य थ्रेड कोड new Thread(new Runnable() { ... कोड के साथ अपना पहला नया थ्रेड (इसे थ्रेड # 2 पर कॉल करें) शुरू करता है। थ्रेड # 2 कॉल alphonse.bow(gaston), synchronizedalphonseFriend ऑब्जेक्ट पर है। थ्रेड # 2 इस प्रकार alphonse ऑब्जेक्ट के लिए "लॉक" प्राप्त करता है और bow विधि में प्रवेश करता है।
  3. एक समय स्लाइस यहां होता है और मूल थ्रेड को अधिक प्रसंस्करण करने का मौका मिलता है।
  4. मुख्य थ्रेड एक दूसरा नया थ्रेड शुरू करता है (इसे थ्रेड # 3 कहते हैं), बस पहले की तरह। थ्रेड # 3 कॉल gaston.bow(alphonse), जो gastonFriend ऑब्जेक्ट पर सिंक्रनाइज़ किया गया है। चूंकि किसी ने अभी तक gaston ऑब्जेक्ट इंस्टेंस के लिए "लॉक" हासिल नहीं किया है, इसलिए थ्रेड # 3 सफलतापूर्वक इस लॉक को प्राप्त करता है और bow विधि में प्रवेश करता है।
  5. एक समय स्लाइस यहां होता है और थ्रेड # 2 को अधिक प्रोसेसिंग करने का मौका मिलता है।
  6. थ्रेड # 2 अब gaston के उदाहरण के संदर्भ में bower.bowBack(this); पर कॉल करता है। यह gaston.bowBack(alphonse) की कॉल के तार्किक समतुल्य है। इस प्रकार, gaston उदाहरण पर यह विधि synchronized है। इस ऑब्जेक्ट के लिए लॉक पहले ही अधिग्रहित कर लिया गया है और इसे किसी अन्य थ्रेड (थ्रेड # 3) द्वारा आयोजित किया जाता है। इस प्रकार, थ्रेड # 2 को रिलीज़ होने के लिए gaston पर लॉक के लिए प्रतीक्षा करनी है। थ्रेड को एक प्रतीक्षा स्थिति में रखा जाता है, जिससे आगे बढ़ने के लिए थ्रेड # 3 की अनुमति मिलती है।
  7. थ्रेड # 3 अब bowback पर कॉल करता है, जो इस उदाहरण में तर्कसंगत रूप से कॉल alphonse.bowBack(gaston) के समान है। ऐसा करने के लिए, इसे alphonse उदाहरण के लिए लॉक प्राप्त करने की आवश्यकता है, लेकिन यह लॉक थ्रेड # 2 द्वारा आयोजित किया जाता है। यह थ्रेड अब एक प्रतीक्षा राज्य में डाल दिया गया है।

और अब आप ऐसी स्थिति में हैं जहां न तो थ्रेड निष्पादित हो सकता है। थ्रेड # 2 और थ्रेड # 3 दोनों लॉक जारी होने की प्रतीक्षा कर रहे हैं। लेकिन थ्रेड बनाने की प्रगति के बिना न तो लॉक जारी किया जा सकता है। लेकिन लॉक जारी किए बिना न तो धागा प्रगति कर सकता है।

इस प्रकार: डेडलॉक!

डेडलॉक्स अक्सर घटनाओं के एक विशिष्ट अनुक्रम पर निर्भर करते हैं, जो तब डीबग करना मुश्किल हो सकता है क्योंकि उन्हें पुन: पेश करना मुश्किल हो सकता है।

+2

ओह ठीक है। तो ताला पूरी वस्तु से संबंधित है। मुझे नहीं पता कि मैंने क्यों सोचा था कि यह अवरुद्ध किए गए किसी दिए गए ऑब्जेक्ट के लिए सिंक्रनाइज़ विधि के लिए बस कॉल किया गया था। मुझे लगता है कि मेरे प्रश्न का उत्तर दें। –

+0

ऑब्जेक्ट सिंक्रनाइज़/लॉक नहीं करता है, बल्कि यह धागा है। –

+1

असल में, मैंने विशेष रूप से लॉक प्राप्त करने वाले थ्रेड के बारे में बात की, लेकिन मुझे लगता है कि मेरी कुछ भाषा अतुलनीय है। मैं इसे और अधिक स्पष्ट कर दूंगा। – Eddie

2

Synchronized has two effects:

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

तो संक्षेप में, यह एक ही ऑब्जेक्ट पर सिंक्रनाइज़ किए गए तरीकों के किसी भी आमंत्रण को अवरुद्ध करता है।

2

एक ही ऑब्जेक्ट के लिए सभी सिंक्रनाइज़ फ़ंक्शंस। "सिंक्रनाइज़" विधि को चिह्नित करना विधि के संपूर्ण सामग्री के आसपास "सिंक्रनाइज़ (यह) {" ब्लॉक डालने जैसा ही है। कारण मैं "समान" नहीं कहता क्योंकि मुझे पता नहीं है कि संकलक एक ही बाइटकोड उत्सर्जित करता है या नहीं, लेकिन परिभाषित रनटाइम प्रभाव AFAIK समान है।

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

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

2

सिंक्रनाइज़ विधि एक

synchronized(this) { 
    /// code here ... 
} 

ब्लॉक में ये सभी पद्धतियां कोड enclosing के समान है।

एक दिया वस्तु उदाहरण के लिए ओ, एक समय में केवल एक धागा किसी भी सिंक्रनाइज़ (ओ) ब्लॉक चला सकते हैं। प्रत्येक ब्लॉक जो कि कोशिश करता है, जब तक कि उस ब्लॉक को चलाने वाले धागे तक (सिंक्रनाइज़ लॉक पर) उस ब्लॉक से बाहर निकलता है (लॉक को छोड़ देता है)।

आपके मामले में, डेडलॉक तब होता है जब अल्फॉन्स थ्रेड 1 में झुकना शुरू करता है, इस प्रकार सिंक्रनाइज़ ब्लॉक में प्रवेश करता है। थ्रेड 1 तब सिस्टम द्वारा स्वैप हो जाता है, इसलिए थ्रेड 2 शुरू हो सकता है, और गैस्टन झुकाव हो सकता है। लेकिन गैस्टन अभी तक वापस नहीं आ सकता है, क्योंकि यह अल्फोन्स पर सिंक्रनाइज़ कर रहा है, और थ्रेड 1 में पहले से ही लॉक है। इस प्रकार यह ब्लॉक छोड़ने के लिए थ्रेड 1 की प्रतीक्षा करेगा। सिस्टम तब थ्रेड 1 को वापस ले जाएगा, जो अल्फोन्स धनुष वापस करने की कोशिश करेगा। सिवाय इसके कि ऐसा नहीं कर सकता क्योंकि थ्रेड 2 में गैस्टन पर सिंक्रनाइज़ लॉक है। दोनों थ्रेड अब फंस गए हैं, दूसरे को झुकने में सक्षम होने से पहले झुकने के लिए इंतजार कर रहे हैं ...

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