एक प्रोग्राम लिखें जो निश्चित रूप से गतिरोध में जाएगा [बंद]


86

मुझे हाल ही में एक साक्षात्कार में पूछे गए यह प्रश्न मिले।

मैंने जवाब दिया कि यदि इंटरलेविंग गलत हो जाता है, तो गतिरोध होता है, लेकिन साक्षात्कारकर्ता ने जोर देकर कहा कि एक ऐसा कार्यक्रम जो हमेशा इंटरलॉकिंग की परवाह किए बिना गतिरोध में जाएगा।

क्या हम ऐसा कार्यक्रम लिख सकते हैं? क्या आप मुझे उस तरह के कुछ उदाहरण कार्यक्रम की ओर इशारा कर सकते हैं?


3
साक्षात्कारकर्ता निश्चित रूप से एक मूर्ख साथी है।
सिंह

23
साक्षात्कारकर्ता निश्चित रूप से एक मूर्ख साथी नहीं है। किसी विषय की पूर्ण समझ का मतलब है कि आपको ध्रुवीय किनारे के मामलों की व्याख्या करने में सक्षम होना चाहिए: कभी भी लॉक न करने और हमेशा लॉक करने का कार्यक्रम बनाना।
यूरी जुबेरव

जवाबों:


100

अद्यतन: यह प्रश्न जनवरी 2013 में मेरे ब्लॉग का विषय था । महान प्रश्न के लिए धन्यवाद!


हम एक कार्यक्रम कैसे लिख सकते हैं जो हमेशा गतिरोध में चले जाएंगे चाहे धागे कैसे निर्धारित हों?

यहाँ C # में एक उदाहरण दिया गया है। ध्यान दें कि प्रोग्राम में कोई लॉक नहीं है और कोई साझा डेटा नहीं है। इसमें केवल एक ही स्थानीय चर और तीन कथन हैं, और फिर भी यह 100% निश्चितता के साथ गतिरोध करता है। एक कठिन कार्यक्रम के साथ आने के लिए कड़ी मेहनत की जाएगी जो निश्चितता के साथ गतिरोध करता है।

पाठक # 1 को व्यायाम करें: समझाएं कि यह गतिरोध कैसा है। (एक उत्तर टिप्पणियों में है।)

पाठक # 2 के लिए व्यायाम करें: जावा में उसी गतिरोध को प्रदर्शित करें। (एक उत्तर यहां है: https://stackoverflow.com/a/9286697/88656 )

class MyClass
{
  static MyClass() 
  {
    // Let's run the initialization on another thread!
    var thread = new System.Threading.Thread(Initialize);
    thread.Start();
    thread.Join();
  }

  static void Initialize() 
  { /* TODO: Add initialization code */ }

  static void Main() 
  { }
}

4
सैद्धांतिक C # का मेरा ज्ञान सीमित है, लेकिन मुझे लगता है कि क्लास लोडर गारंटी देता है कि कोड एकल थ्रेडेड है जैसा कि यह जावा में चलता है। मुझे पूरा यकीन है कि जावा पज़लर्स में एक समान उदाहरण है।
वू

11
@Voo: आपके पास एक अच्छी मेमोरी है। नील गेर - "जावा पज़लर्स" के सह-लेखक - और मैंने कुछ साल पहले ओस्लो डेवलपर कॉन्फ्रेंस में हमारी "सी # पज़्लर्स" वार्ता में इस कोड का एक अधिक अस्पष्ट संस्करण प्रस्तुत किया।
एरिक लिपर्ट

41
@Lieven: स्थिर निर्माता से अधिक नहीं चलाना चाहिए एक बार और इसे चलाने चाहिए से पहले वर्ग में किसी भी स्थिर विधि करने के लिए पहली कॉल। मुख्य एक स्थिर विधि है, इसलिए मुख्य धागा स्टेटिक कॉटर को कॉल करता है। यह सुनिश्चित करने के लिए कि यह केवल एक बार चलता है, सीएलआर एक ताला निकालता है जो तब तक जारी नहीं किया जाता है जब तक कि स्थिर ctor खत्म नहीं हो जाता। जब ctor एक नया धागा शुरू करता है, तो वह धागा एक स्थैतिक विधि भी कहता है, इसलिए CLR लॉक को यह देखने की कोशिश करता है कि क्या उसे ctor चलाने की आवश्यकता है। मुख्य धागा इस बीच अवरुद्ध धागे को "जोड़ता है", और अब हमारे पास हमारा गतिरोध है।
एरिक लिपर्ट

33
@ सारब्रिस्टल: मैंने कभी जावा कोड की एक पंक्ति के रूप में इतना नहीं लिखा है; मुझे अब शुरू करने का कोई कारण नहीं दिख रहा है।
एरिक लिपिपर्ट

4
ओह, मैंने मान लिया कि आपके पास आपके व्यायाम # 2 का उत्तर है। एक जावा प्रश्न का उत्तर देने के लिए यह कई upvotes प्राप्त करने पर बधाई देता है।
आर्टब्रिस्टल

27

यहाँ कुंडी सुनिश्चित करती है कि दोनों ताले तब लगे जब प्रत्येक धागा दूसरे को लॉक करने की कोशिश करे:

import java.util.concurrent.CountDownLatch;

public class Locker extends Thread {

   private final CountDownLatch latch;
   private final Object         obj1;
   private final Object         obj2;

   Locker(Object obj1, Object obj2, CountDownLatch latch) {
      this.obj1 = obj1;
      this.obj2 = obj2;
      this.latch = latch;
   }

   @Override
   public void run() {
      synchronized (obj1) {

         latch.countDown();
         try {
            latch.await();
         } catch (InterruptedException e) {
            throw new RuntimeException();
         }
         synchronized (obj2) {
            System.out.println("Thread finished");
         }
      }

   }

   public static void main(String[] args) {
      final Object obj1 = new Object();
      final Object obj2 = new Object();
      final CountDownLatch latch = new CountDownLatch(2);

      new Locker(obj1, obj2, latch).start();
      new Locker(obj2, obj1, latch).start();

   }

}

जंक कंसोल चलाने के लिए दिलचस्प, जो आपको थ्रेड्स टैब में गतिरोध को सही ढंग से दिखाएगा।


3
यह अब तक का सबसे अच्छा है, लेकिन मैं sleepएक उचित कुंडी से बदलूंगा: सैद्धांतिक रूप से, हमारे यहां एक दौड़ की स्थिति है। हालांकि हम लगभग सुनिश्चित कर सकते हैं कि 0.5 सेकंड पर्याप्त है, यह एक साक्षात्कार कार्य के लिए बहुत अच्छा नहीं है।
अल्फ

25

डेडलॉक तब होता है जब थ्रेड्स (या जो भी आपका प्लेटफॉर्म अपनी निष्पादन इकाइयों को कॉल करता है) संसाधन प्राप्त करते हैं, जहां प्रत्येक संसाधन को केवल एक समय में एक थ्रेड द्वारा रखा जा सकता है, और उन संसाधनों को इस तरह से रखता है कि होल्ड को पूर्व निर्धारित नहीं किया जा सकता है, और थ्रेड्स के बीच कुछ "परिपत्र" संबंध मौजूद है जैसे कि डेडलॉक में प्रत्येक थ्रेड किसी अन्य थ्रेड द्वारा आयोजित कुछ संसाधन प्राप्त करने के लिए प्रतीक्षा कर रहा है।

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

दो धागे, दो ताले। पहला धागा एक लूप चलाता है जो एक निश्चित क्रम में तालों को प्राप्त करने का प्रयास करता है, दूसरा धागा एक लूप चलाता है जो विपरीत क्रम में ताले प्राप्त करने का प्रयास करता है। प्रत्येक थ्रेड ताले को सफलतापूर्वक प्राप्त करने के बाद दोनों ताले जारी करता है।

public class HighlyLikelyDeadlock {
    static class Locker implements Runnable {
        private Object first, second;

        Locker(Object first, Object second) {
            this.first = first;
            this.second = second;
        }

        @Override
        public void run() {
            while (true) {
                synchronized (first) {
                    synchronized (second) {
                        System.out.println(Thread.currentThread().getName());
                    }
                }
            }
        }
    }

    public static void main(final String... args) {
        Object lock1 = new Object(), lock2 = new Object();
        new Thread(new Locker(lock1, lock2), "Thread 1").start();
        new Thread(new Locker(lock2, lock1), "Thread 2").start();
    }
}

अब, इस प्रश्न में कुछ टिप्पणियाँ दी गई हैं जो संभावना और गतिरोध की निश्चितता के बीच अंतर को इंगित करती हैं । कुछ अर्थों में, भेद एक शैक्षणिक मुद्दा है। एक व्यावहारिक दृष्टिकोण से, मैं निश्चित रूप से एक रनिंग सिस्टम देखना चाहता हूं जो मेरे द्वारा लिखे गए कोड के साथ गतिरोध नहीं करता है :)

हालांकि, साक्षात्कार के प्रश्न कई बार अकादमिक हो सकते हैं, और यह SO प्रश्न शीर्षक में "निश्चित रूप से" शब्द होता है, इसलिए निम्नानुसार एक प्रोग्राम है जो निश्चित रूप से गतिरोध है। दो Lockerऑब्जेक्ट बनाए जाते हैं, प्रत्येक को दो ताले दिए जाते हैं और CountDownLatchथ्रेड्स के बीच सिंक्रनाइज़ करने के लिए उपयोग किया जाता है। प्रत्येक Lockerलॉक को पहले लॉक किया जाता है फिर एक बार कुंडी को नीचे गिना जाता है। जब दोनों थ्रेड्स ने एक लॉक हासिल कर लिया है और कुंडी को गिना है, तो वे लैच बैरियर को आगे बढ़ाते हैं और एक दूसरे लॉक को हासिल करने का प्रयास करते हैं, लेकिन प्रत्येक मामले में दूसरे धागे में पहले से ही वांछित लॉक होता है। इस स्थिति के परिणामस्वरूप एक निश्चित गतिरोध होता है।

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class CertainDeadlock {
    static class Locker implements Runnable {
        private CountDownLatch latch;
        private Lock first, second;

        Locker(CountDownLatch latch, Lock first, Lock second) {
            this.latch = latch;
            this.first = first;
            this.second = second;
        }

        @Override
        public void run() {
            String threadName = Thread.currentThread().getName();
            try {
                first.lock();
                latch.countDown();
                System.out.println(threadName + ": locked first lock");
                latch.await();
                System.out.println(threadName + ": attempting to lock second lock");
                second.lock();
                System.out.println(threadName + ": never reached");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(final String... args) {
        CountDownLatch latch = new CountDownLatch(2);
        Lock lock1 = new ReentrantLock(), lock2 = new ReentrantLock();
        new Thread(new Locker(latch, lock1, lock2), "Thread 1").start();
        new Thread(new Locker(latch, lock2, lock1), "Thread 2").start();
    }
}

3
लिनस को उद्धृत करने के लिए क्षमा करें, "टॉक सस्ता है। मुझे कोड दिखाएं।" - यह एक अच्छा काम है, और यह आश्चर्यजनक रूप से कठिन है जितना लगता है।
अल्फ

2
इस कोड को गतिरोध के बिना चलाना संभव है
व्लादिमीर ज़िलाएव

1
ठीक है, आप लोग क्रूर हैं, लेकिन मुझे लगता है कि यह अब एक पूर्ण उत्तर है।
ग्रेग मैट्स

@GregMattes धन्यवाद :) कुछ भी नहीं जोड़ा जा सकता है, लेकिन +1, और आशा है कि आपने मज़ा किया :)
alf

15

एरिक लिपर्ट के एक के बाद एक जावा उदाहरण है:

public class Lock implements Runnable {

    static {
        System.out.println("Getting ready to greet the world");
        try {
            Thread t = new Thread(new Lock());
            t.start();
            t.join();
        } catch (InterruptedException ex) {
            System.out.println("won't see me");
        }
    }

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }

    public void run() {           
        Lock lock = new Lock();      
    }

}

4
मुझे लगता है कि रन मेथड में शामिल होना थोड़ा भ्रामक है। यह पता चलता है कि स्टैटिक ब्लॉक में एक के अलावा यह अन्य जुड़ने के लिए एक गतिरोध प्राप्त करने की आवश्यकता होती है जबकि गतिरोध "नए लॉक ()" कथन के कारण होता है। मेरे पुन: लिखने, C # उदाहरण में स्थिर विधि का उपयोग करते हुए: stackoverflow.com/a/16203272/2098232
luke657

क्या आप अपना उदाहरण बता सकते हैं?
gstackoverflow

मेरे प्रयोगों के अनुसार t.join (); इनसाइड रन () मेथड बेमानी है
gstackoverflow

मैंने अनावश्यक कोड हटा दिया, जो समझ में आने से रोकता है
gstackoverflow

11

यहाँ प्रलेखन से एक उदाहरण है:

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();
    }
}

2
+1 जावा ट्यूटोरियल जोड़ने के लिए।
MRE

4
"यह बहुत संभावना है" के लिए पर्याप्त नहीं है "निश्चित रूप से गतिरोध में जाएगा"
अल्फ

1
@alf ओह, लेकिन मौलिक मुद्दे को यहाँ बहुत अच्छी तरह से प्रदर्शित किया गया है। एक राउंड रॉबिन अनुसूचक लिख सकता है जो एक Object invokeAndWait(Callable task)विधि को उजागर करता है । फिर सभी Callable t1को लौटने से पहले अपने जीवन के समय के invokeAndWait()लिए करना पड़ता है Callable t2, और इसके विपरीत।
user268396

2
@ user268396 अच्छी तरह से, मूल मुद्दा तुच्छ और उबाऊ है :) कार्य का पूरा बिंदु यह पता लगाना है - या यह साबित करना है कि आप समझते हैं - कि एक गारंटीकृत गतिरोध प्राप्त करना आश्चर्यजनक रूप से कठिन है (और साथ ही एक अतुल्यकालिक दुनिया में किसी भी चीज़ की गारंटी देना है) )।
अल्फ

4
@bezz sleepबोरिंग है। जबकि मेरा मानना ​​है कि 5 सेकंड के लिए कोई धागा शुरू नहीं होगा, यह वैसे भी एक दौड़ की स्थिति है। आप एक प्रोग्रामर को किराए पर नहीं लेना चाहते हैं, जो sleep()दौड़ की स्थिति को हल करने में भरोसा करेंगे :)
alf

9

मैंने एरिक लिपर्ट द्वारा पोस्ट किए गए डेडलॉक उदाहरण के यूरी जुबेरव के जावा संस्करण को फिर से लिखा है: https://stackoverflow.com/a/9286697/2098232 अधिक बारीकी से C # संस्करण जैसा दिखता है। यदि जावा का इनिशियलाइज़ेशन ब्लॉक समान रूप से C # स्टैटिक कंस्ट्रक्टर के लिए काम करता है और पहले लॉक को प्राप्त करता है तो हमें गतिरोध प्राप्त करने के लिए ज्वाइन विधि को भी लागू करने के लिए किसी अन्य थ्रेड की आवश्यकता नहीं है, इसे केवल लॉक क्लास से कुछ स्टैटिक विधि की आवश्यकता है, जैसे कि ओरिजिनल # उदाहरण। परिणामी गतिरोध इसकी पुष्टि करता है।

public class Lock {

    static {
        System.out.println("Getting ready to greet the world");
        try {
            Thread t = new Thread(new Runnable(){

                @Override
                public void run() {
                    Lock.initialize();
                }

            });
            t.start();
            t.join();
        } catch (InterruptedException ex) {
            System.out.println("won't see me");
        }
    }

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }

    public static void initialize(){
        System.out.println("Initializing");
    }

}

जब मैं रन-वे विधि में Lock.initialize () टिप्पणी करता हूं, तो यह गतिरोध नहीं है? प्रारंभिक विधि हालांकि कुछ भी नहीं करता है ??
असितात्स

@ असमानता केवल एक अनुमान है लेकिन विधि को अनुकूलित किया जा सकता है; इस बारे में निश्चित नहीं है कि यह थ्रेड्स के साथ कैसे काम करेगा
डेव कूसिन्यू

5

यह एक सरल साक्षात्कार कार्य नहीं है जिसे आप प्राप्त कर सकते हैं: मेरी परियोजना में, इसने पूरे दिन के लिए टीम के काम को पंगु बना दिया। अपने कार्यक्रम को रोकना बहुत आसान है, लेकिन इसे उस राज्य में ले जाना बहुत कठिन है जहां थ्रेड डंप कुछ ऐसा लिखता है,

Found one Java-level deadlock:
=============================
"Thread-2":
  waiting to lock monitor 7f91c5802b58 (object 7fb291380, a java.lang.String),
  which is held by "Thread-1"
"Thread-1":
  waiting to lock monitor 7f91c6075308 (object 7fb2914a0, a java.lang.String),
  which is held by "Thread-2"

Java stack information for the threads listed above:
===================================================
"Thread-2":
    at uk.ac.ebi.Deadlock.run(Deadlock.java:54)
    - waiting to lock <7fb291380> (a java.lang.String)
    - locked <7fb2914a0> (a java.lang.String)
    - locked <7f32a0760> (a uk.ac.ebi.Deadlock)
    at java.lang.Thread.run(Thread.java:680)
"Thread-1":
    at uk.ac.ebi.Deadlock.run(Deadlock.java:54)
    - waiting to lock <7fb2914a0> (a java.lang.String)
    - locked <7fb291380> (a java.lang.String)
    - locked <7f32a0580> (a uk.ac.ebi.Deadlock)
    at java.lang.Thread.run(Thread.java:680)

तो लक्ष्य एक गतिरोध प्राप्त करना होगा जिसे JVM गतिरोध पर विचार करेगा। जाहिर है, जैसे कोई समाधान नहीं

synchronized (this) {
    wait();
}

उस अर्थ में काम करेंगे, भले ही वे वास्तव में हमेशा के लिए बंद हो जाएंगे। एक दौड़ की स्थिति पर भरोसा करना एक अच्छा विचार नहीं है, या तो, जैसा कि साक्षात्कार के दौरान आप आमतौर पर कुछ साबित करने के लिए काम करना चाहते हैं, न कि कुछ जो कि ज्यादातर समय काम करना चाहिए।

अब, sleep()समाधान एक अर्थ में ठीक है, ऐसी स्थिति की कल्पना करना कठिन है जहां यह काम नहीं करता है, लेकिन उचित नहीं है (हम निष्पक्ष हैं, हम नहीं हैं?)। @Artbristol (मेरा एक ही है, सिर्फ अलग-अलग ऑब्जेक्ट्स पर नज़र रखता है) द्वारा समाधान अच्छा है, लेकिन लंबे समय तक और सही स्थिति में थ्रेड्स प्राप्त करने के लिए नई संगामिति आदिम का उपयोग करता है, जो इतना मज़ेदार नहीं है:

public class Deadlock implements Runnable {
    private final Object a;
    private final Object b;
    private final static CountDownLatch latch = new CountDownLatch(2);

    public Deadlock(Object a, Object b) {
        this.a = a;
        this.b = b;
    }

    public synchronized static void main(String[] args) throws InterruptedException {
        new Thread(new Deadlock("a", "b")).start();
        new Thread(new Deadlock("b", "a")).start();
    }

    @Override
    public void run() {
        synchronized (a) {
            latch.countDown();
            try {
                latch.await();
            } catch (InterruptedException ignored) {
            }
            synchronized (b) {
            }
        }
    }
}

मुझे याद है कि synchronized-only समाधान कोड की 11..13 पंक्तियों (टिप्पणियों और आयातों को छोड़कर) में फिट बैठता है, लेकिन वास्तविक चाल को याद नहीं करना है। अगर मैं करूँगा तो अद्यतन करेगा।

अद्यतन: यहाँ पर एक बदसूरत समाधान है synchronized:

public class Deadlock implements Runnable {
    public synchronized static void main(String[] args) throws InterruptedException {
        synchronized ("a") {
            new Thread(new Deadlock()).start();
            "a".wait();
        }
        synchronized ("") {
        }
    }

    @Override
    public void run() {
        synchronized ("") {
            synchronized ("a") {
                "a".notifyAll();
            }
            synchronized (Deadlock.class) {
            }
        }
    }
}

ध्यान दें कि हम एक ऑब्जेक्ट मॉनिटर ( "a"ऑब्जेक्ट के रूप में उपयोग ) के साथ एक कुंडी बदलते हैं ।


हम सोचते हैं कि यह एक उचित साक्षात्कार कार्य है। यह आपको वास्तव में जावा में गतिरोध और लॉकिंग को समझने के लिए कहता है। मुझे नहीं लगता कि सामान्य विचार यह है कि मुश्किल या तो (यह सुनिश्चित करें कि दोनों धागे केवल अपने पहले संसाधन को बंद करने के बाद ही जारी रह सकते हैं), आपको बस काउंटडाउनचैट याद रखना चाहिए - लेकिन साक्षात्कारकर्ता के रूप में मैं उस भाग में साक्षात्कारकर्ता की मदद करूंगा। अगर वह समझा सकता है कि वास्तव में उसे क्या चाहिए (यह एक ऐसा वर्ग नहीं है जिसकी सबसे अधिक देवों को कभी आवश्यकता होती है और आप एक साक्षात्कार में इसके लिए Google नहीं कर सकते हैं)। मुझे इंटरव्यू के लिए इस तरह के दिलचस्प सवाल करना पसंद है!
Voo

@ उस समय जब हम इसके साथ खेल रहे थे, उस समय JDK में कोई कुंडी नहीं थी, इसलिए यह सब हाथ से गया था। और बीच का अंतर LOCKEDऔर waiting to lockसूक्ष्म कुछ आप नाश्ते के दौरान पढ़ा है, नहीं। लेकिन ठीक है, तुम शायद सही हो। मुझे rephrase करते हैं।
अल्फ

4

यह सी # संस्करण, मुझे लगता है कि जावा बहुत समान होना चाहिए।

static void Main(string[] args)
{
    var mainThread = Thread.CurrentThread;
    mainThread.Join();

    Console.WriteLine("Press Any key");
    Console.ReadKey();
}

2
अच्छा था! यदि आप consoleकथनों को हटाते हैं, तो गतिरोध पैदा करने के लिए कम से कम C # प्रोग्राम को सच में देखें । आप बस के Mainरूप में पूरे समारोह लिख सकते हैं Thread.CurrentThread.Join();
आरबीटी

3
import java.util.concurrent.CountDownLatch;

public class SO8880286 {
    public static class BadRunnable implements Runnable {
        private CountDownLatch latch;

        public BadRunnable(CountDownLatch latch) {
            this.latch = latch;
        }

        public void run() {
            System.out.println("Thread " + Thread.currentThread().getId() + " starting");
            synchronized (BadRunnable.class) {
                System.out.println("Thread " + Thread.currentThread().getId() + " acquired the monitor on BadRunnable.class");
                latch.countDown();
                while (true) {
                    try {
                        latch.await();
                    } catch (InterruptedException ex) {
                        continue;
                    }
                    break;
                }
            }
            System.out.println("Thread " + Thread.currentThread().getId() + " released the monitor on BadRunnable.class");
            System.out.println("Thread " + Thread.currentThread().getId() + " ending");
        }
    }

    public static void main(String[] args) {
        Thread[] threads = new Thread[2];
        CountDownLatch latch = new CountDownLatch(threads.length);
        for (int i = 0; i < threads.length; ++i) {
            threads[i] = new Thread(new BadRunnable(latch));
            threads[i].start();
        }
    }
}

प्रोग्राम हमेशा गतिरोध करता है क्योंकि प्रत्येक थ्रेड दूसरे थ्रेड्स के लिए बैरियर पर प्रतीक्षा कर रहा है, लेकिन बैरियर का इंतजार करने के लिए, थ्रेड को मॉनिटर पर रखना होगा BadRunnable.class


3
} catch (InterruptedException ex) { continue; }... सुंदर
आर्टब्रिस्टल

2

यहाँ जावा में एक उदाहरण है

http://baddotrobot.com/blog/2009/12/24/deadlock/

जहां एक अपहरणकर्ता गतिरोध में हो जाता है जब वह पीड़ित को तब तक देने से इंकार कर देता है जब तक कि वह नकदी प्राप्त नहीं कर लेता है लेकिन वार्ताकार नकदी तब तक देने से इंकार कर देता है जब तक कि वह पीड़ित को प्राप्त नहीं कर लेता।


यह कार्यान्वयन जैसा कि दिया गया है, प्रासंगिक नहीं है। कोड के कुछ टुकड़े गायब प्रतीत होते हैं। हालाँकि, जिस सामान्य विचार को आप व्यक्त करते हैं वह सही है क्योंकि संसाधन विवाद में गतिरोध है।
मास्टर चीफ

उदाहरण शैक्षणिक है, इसलिए मैं उत्सुक हूं कि आप इसकी व्याख्या क्यों नहीं करते हैं ... अनुपलब्ध कोड खाली विधियां हैं जहां विधि नाम सहायक माना जाता है (लेकिन संक्षिप्तता के लिए नहीं दिखाया गया है)
टोबी

1

एक साधारण खोज ने मुझे निम्नलिखित कोड दिया:

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();
    }
}

स्रोत: गतिरोध


3
"यह बहुत संभावना है" के लिए पर्याप्त नहीं है "निश्चित रूप से गतिरोध में चला जाएगा"
अल्फ

1

यहां नमूना है जहां एक थ्रेड होल्ड लॉक से एक और थ्रेड शुरू होता है जो एक ही लॉक चाहता है और फिर स्टार्टर खत्म होने तक इंतजार करता है ... हमेशा के लिए:

class OuterTask implements Runnable {
    private final Object lock;

    public OuterTask(Object lock) {
        this.lock = lock;
    }

    public void run() {
        System.out.println("Outer launched");
        System.out.println("Obtaining lock");
        synchronized (lock) {
            Thread inner = new Thread(new InnerTask(lock), "inner");
            inner.start();
            try {
                inner.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class InnerTask implements Runnable {
    private final Object lock;

    public InnerTask(Object lock) {
        this.lock = lock;
    }

    public void run() {
        System.out.println("Inner launched");
        System.out.println("Obtaining lock");
        synchronized (lock) {
            System.out.println("Obtained");
        }
    }
}

class Sample {
    public static void main(String[] args) throws InterruptedException {
        final Object outerLock = new Object();
        OuterTask outerTask = new OuterTask(outerLock);
        Thread outer = new Thread(outerTask, "outer");
        outer.start();
        outer.join();
    }
}

0

यहाँ एक उदाहरण है:

दो धागे चल रहे हैं, प्रत्येक एक दूसरे को लॉक जारी करने की प्रतीक्षा कर रहा है

सार्वजनिक वर्ग थ्रेडक्लास थ्रेड का विस्तार करता है {

String obj1,obj2;
ThreadClass(String obj1,String obj2){
    this.obj1=obj1;
    this.obj2=obj2;
    start();
}

public void run(){
    synchronized (obj1) {
        System.out.println("lock on "+obj1+" acquired");

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("waiting for "+obj2);
        synchronized (obj2) {
            System.out.println("lock on"+ obj2+" acquired");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }


}

}

इसे चलाने से गतिरोध उत्पन्न होगा:

सार्वजनिक वर्ग SureDeadlock {

public static void main(String[] args) {
    String obj1= new String("obj1");
    String obj2= new String("obj2");

    new ThreadClass(obj1,obj2);
    new ThreadClass(obj2,obj1);


}

}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.