डेडलॉक तब होता है जब थ्रेड्स (या जो भी आपका प्लेटफॉर्म अपनी निष्पादन इकाइयों को कॉल करता है) संसाधन प्राप्त करते हैं, जहां प्रत्येक संसाधन को केवल एक समय में एक थ्रेड द्वारा रखा जा सकता है, और उन संसाधनों को इस तरह से रखता है कि होल्ड को पूर्व निर्धारित नहीं किया जा सकता है, और थ्रेड्स के बीच कुछ "परिपत्र" संबंध मौजूद है जैसे कि डेडलॉक में प्रत्येक थ्रेड किसी अन्य थ्रेड द्वारा आयोजित कुछ संसाधन प्राप्त करने के लिए प्रतीक्षा कर रहा है।
इसलिए, गतिरोध से बचने का एक आसान तरीका संसाधनों के लिए कुल आदेश देना है और एक नियम लागू करना है कि संसाधनों को केवल क्रम में थ्रेड द्वारा अधिग्रहित किया जाता है । इसके विपरीत, संसाधनों को प्राप्त करने वाले थ्रेड्स को चलाकर जानबूझकर गतिरोध पैदा किया जा सकता है, लेकिन उन्हें क्रम में प्राप्त न करें। उदाहरण के लिए:
दो धागे, दो ताले। पहला धागा एक लूप चलाता है जो एक निश्चित क्रम में तालों को प्राप्त करने का प्रयास करता है, दूसरा धागा एक लूप चलाता है जो विपरीत क्रम में ताले प्राप्त करने का प्रयास करता है। प्रत्येक थ्रेड ताले को सफलतापूर्वक प्राप्त करने के बाद दोनों ताले जारी करता है।
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();
}
}