2011-08-23 21 views
5

मैं बहुत साधारण प्रोग्राम है जो साधारण गतिरोध, जहां संसाधन एक के लिए धागा एक प्रतीक्षा करता संसाधन बी के लिए थ्रेड बी और थ्रेड बी प्रतीक्षा करता है के द्वारा बंद कर थ्रेड ए द्वारा बंद कर नकल लिखने के लिए कोशिश कर रहा हूँनवागंतुकों के लिए जावा - गतिरोध नकली

//it will be my Shared resource 
public class Account { 
    private float amount; 

    public void debit(double amount){ 
     this.amount-=amount; 
    } 

    public void credit(double amount){ 
     this.amount+=amount; 
    } 

} 

यह मेरा runnable है जो ऊपर संसाधन पर ऑपरेशन करता है::

public class BankTransaction implements Runnable { 
    Account fromAccount,toAccount; 
    float ammount; 
    public BankTransaction(Account fromAccount, Account toAccount,float ammount){ 
     this.fromAccount = fromAccount; 
     this.toAccount = toAccount; 
     this.ammount = ammount; 
    } 

    private void transferMoney(){ 
     synchronized(fromAccount){ 
      synchronized(toAccount){ 
       fromAccount.debit(ammount); 
       toAccount.credit(ammount); 
       try { 
        Thread.sleep(500); 
       } catch (InterruptedException e) { 
       e.printStackTrace(); 
       } 
       System.out.println("Current Transaction Completed!!!"); 
      } 
     } 
    } 

    @Override 
    public void run() { 
     transferMoney(); 
    } 

} 

और अंत में अपने मुख्य वर्ग:

यहाँ मेरी कोड है

public static void main(String[] args) { 

    Account a = new Account(); 
    Account b = new Account(); 
    Thread thread1 = new Thread(new BankTransaction(a,b,500)); 

    Thread thread2 = new Thread(new BankTransaction(b,a,500)); 
     thread1.start(); 
     thread2.start(); 
System.out.println("Transactions Completed!!!"); 

    } 
} 

यह कोड सफलतापूर्वक निष्पादित क्यों चलता है और मेरे पास नहीं है और मृतक है?

उत्तर

10

इसे संभावित डेडलॉक के लिए मिला है - लेकिन दोनों ताले इतनी जल्दी से अधिग्रहित किए जाते हैं कि एक थ्रेड दोनों को पहले प्राप्त करने का मौका मिलने से पहले दोनों ही मिल सकते हैं।

दो सिंक्रनाइज़ बयानों के बीच एक और Thread.sleep(500); कॉल रखो और यह गतिरोध करता है: दोनों धागे "उनके" बाहरी ताला, नींद में प्रवेश करेंगे, तो जब वे जाग वे दोनों मिल जाएगा कि उनके "आंतरिक" लॉक पहले से ही है हासिल कर ली।

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

+0

नींद गैर-निर्धारणा को पेश कर सकती है। आप इसे निर्धारिती बना सकते हैं; नीचे मेरा जवाब देखें। – Toby

+0

@Toby: हाँ, आप इसे निर्धारिती बना सकते हैं - लेकिन 'नींद' यह दिखाने का एक अच्छा तरीका है कि डेडलॉक * कैसा * हो सकता है, क्योंकि आप हमेशा बिना किसी कार्यक्रम के कल्पना कर सकते हैं जो नींद का उपयोग करता है, जो * नींद का उपयोग करता है, बस धागे के आधार पर निर्धारित नहीं किया जा रहा है। दूसरे शब्दों में, एक प्रोग्राम जो नींद डालने पर विफल रहता है वह स्वाभाविक रूप से त्रुटिपूर्ण है क्योंकि आप वास्तविक जीवन में "गलती से" देख सकते हैं। नोटिफिकेशन डालने के साथ भी यह सच नहीं है। –

5

यह संभव है कि धागे में से एक synchronized अनुभागों में प्रवेश करेगा, अन्य धागे को पूरी तरह समाप्त होने तक पूरी तरह अवरुद्ध कर देगा।

4

आपको 'दुर्भाग्यपूर्ण समय' अनुकरण करने की आवश्यकता है। दो ताले के बीच जोड़ने नींद का प्रयास करें:

synchronized(fromAccount){ 
    Thread.sleep(2000); 
    synchronized(toAccount){ 
0

गतिरोध का कारण यह है कि धागा एक है थ्रेड बी के लिए इंतजार कुछ संसाधन जारी करने के लिए एक आगे बढ़ने से पहले की है, थ्रेड बी के समान, यह तब तक जारी नहीं रहेगा जब तक थ्रेड ए कुछ संसाधन जारी नहीं करता है। दूसरे शब्दों में, ए और बी एक दूसरे के लिए हमेशा के लिए इंतजार करते हैं।

कोड स्निपेट में, सिंक्रनाइज़ेशन अन्य थ्रेड को अवरुद्ध कर सकता है क्योंकि इस समय केवल एक थ्रेड ब्लॉक को निष्पादित कर सकता है। thread.sleep() 500 मिलीसेकंद के लिए धागा निलंबित, फिर जारी रखें। प्रतीक्षा हमेशा के लिए पारस्परिक स्थिति संतुष्ट नहीं है, कि यह डेडलॉक क्यों नहीं है।

टुकड़ा के बाद

गतिरोध वर्णन करने के लिए एक अच्छा उदाहरण है

public class threadTest{ 

    public class thread1 implements Runnable{ 
     private Thread _th2; 
     private int _foo; 

     public thread1(Thread th2){}; 
     public void run(){ 
     for(int i = 0; i<100; i++){foo += foo;}; 
     synchronized(this){this.notify()}; 
     synchronized(_th2){ 
      _th2.wait(); 
      _foo += _th2.foo; 
      System.out.print(" final result " + _foo); 
     } 
     } 
    } 

    public class thread2 implements Runnable{ 
     private final thread1 _th1; private int _foo; 
     public thread2(thread1 th1){}; 
     public void Run(){ 
      synchronized(_th1){_th1.wait()}; 
      synchronized(this){ 
      _foo += th1._foo(); 
      this.notify();     
      } 
     } 
    } 
    } 
} 

// सिर्फ वर्ग

क्योंकि वहाँ कोई तंत्र दो धागे के निष्पादन के आदेश आश्वस्त है में निजी चर तक पहुँचने के लिए जिस तरह से उपेक्षा, यह बहुत संभव है थ्रेड 2 थ्रेड 1 से अधिसूचना प्राप्त नहीं करेगा क्योंकि यह हाल ही में शुरू होता है, इस प्रकार यह निष्पादन जारी रखने से पहले अधिसूचना की प्रतीक्षा करता है। थ्रेड 1 के समान, यह तब तक निष्पादन नहीं कर सकता जब तक कि इसे थ्रेड 2 से अधिसूचना प्राप्त न हो जाए। वे दोनों एक दूसरे के लिए हमेशा के लिए इंतजार, ठेठ डेडलॉक।

2

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

उदाहरण के लिए code और blog post इसे थोड़ा वर्णन करते हुए देखें।

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