Deadlock (आपसी ब्लॉकिंग) एक ऐसी स्थिति है जिसमें दो या अधिक थ्रेड अन्य प्रतिभागियों द्वारा कब्जाए गए संसाधनों की रिहाई की अनिश्चित काल तक प्रतीक्षा करते हैं। Oracle Java Tutorials (2024) के अनुसार, Deadlock चक्रीय प्रतीक्षा में होता है जब प्रत्येक थ्रेड एक लॉक रखता है जो दूसरे थ्रेड के लिए आवश्यक है। विशेष डिटेक्शन टूल के बिना, Deadlock बिना दृश्य त्रुटियों के एप्लिकेशन निष्पादन को पूरी तरह से रोक देता है।
मुख्य बिंदु
Deadlock मल्टीथ्रेडेड प्रोग्रामिंग में एक स्थिति है जहां दो या अधिक थ्रेड एक दूसरे को स्थायी रूप से ब्लॉक करते हैं। प्रत्येक थ्रेड दूसरे थ्रेड के लिए आवश्यक संसाधन रखता है और लापता संसाधन प्राप्त करने की प्रतीक्षा करते हुए उसे जारी नहीं करता। परिणामस्वरूप, कोई भी थ्रेड निष्पादन जारी नहीं रख सकता।
मोबाइल डेवलपमेंट में, Deadlock विशेष रूप से महत्वपूर्ण है क्योंकि यह अपवाद या क्रैश नहीं करता। एप्लिकेशन उपयोगकर्ता क्रियाओं का जवाब देना बंद कर देता है (ANR — Application Not Responding), और एकमात्र समाधान प्रक्रिया को जबरन समाप्त करना है। Google (Android Performance Patterns, 2023) के अनुसार, Google Play Console में लगभग 15% ANR रिपोर्ट बैकग्राउंड थ्रेड में आपसी ब्लॉकिंग से संबंधित हैं।
Deadlock और अन्य concurrency समस्याओं के बीच मुख्य अंतर बाहरी हस्तक्षेप के बिना इसकी अपरिवर्तनीयता है। थ्रेड स्वयं संसाधन जारी नहीं करेंगे क्योंकि ऑपरेटिंग सिस्टम शेड्यूलर जबरन लॉक वापस नहीं ले सकता। यह Deadlock को Livelock से अलग करता है, जहां थ्रेड सक्रिय हैं लेकिन उपयोगी कार्य नहीं कर रहे हैं।
1971 में, Edward G. Coffman ने Deadlock उत्पन्न होने के लिए आवश्यक चार अनिवार्य शर्तें तैयार कीं। यदि उनमें से कम से कम एक अनुपस्थित है, तो आपसी ब्लॉकिंग असंभव है। ये शर्तें Coffman की शर्तों के रूप में जानी जाती हैं और सभी Deadlock रोकथाम एल्गोरिदम का आधार बनती हैं।
एक संसाधन केवल एक थ्रेड द्वारा किसी भी समय कब्जा किया जा सकता है। यदि कोई संसाधन कई थ्रेड द्वारा एक साथ पढ़ने की अनुमति देता है (जैसे ReadWriteLock रीड मोड में), तो Deadlock नहीं होता। यह शर्त Mutex और लॉक की प्रकृति से उत्पन्न होती है।
एक थ्रेड पहले से कब्जाए गए संसाधन को रखता है और साथ ही दूसरे संसाधन को प्राप्त करने की प्रतीक्षा करता है। यदि कोई थ्रेड अगले संसाधन का अनुरोध करने से पहले वर्तमान संसाधन को जारी कर सकता है (दो-चरण लॉकिंग के माध्यम से), तो Hold and Wait शर्त टूट जाती है। Android में, यह अक्सर तब प्रकट होता है जब कोई थ्रेड डेटाबेस लॉक रखता है और SharedPreferences लॉक प्राप्त करने का प्रयास करता है।
ऑपरेटिंग सिस्टम किसी थ्रेड से लॉक जबरन नहीं ले सकता। संसाधन तभी जारी होता है जब थ्रेड स्वयं इसे जारी करता है। कुछ सिस्टम में (जैसे SQLite WAL मोड), व्यक्तिगत संचालन के स्तर पर जबरन बेदखली लागू की जाती है, जो Deadlock के जोखिम को कम करती है।
थ्रेड की एक बंद श्रृंखला होती है, जिनमें से प्रत्येक श्रृंखला में अगले थ्रेड द्वारा रखे गए संसाधन की प्रतीक्षा करता है। उदाहरण के लिए, थ्रेड A संसाधन 1 रखता है और संसाधन 2 की प्रतीक्षा करता है, थ्रेड B संसाधन 2 रखता है और संसाधन 1 की प्रतीक्षा करता है। यह एकमात्र शर्त है जिसे डेवलपर आर्किटेक्चरल रूप से समाप्त कर सकता है — लॉक पदानुक्रम के माध्यम से। यदि सभी थ्रेड संसाधनों को सख्ती से परिभाषित वैश्विक क्रम में प्राप्त करते हैं, तो चक्र भौतिक रूप से असंभव है।
व्यवहार में, Android एप्लिकेशन में, Deadlock सबसे अधिक बार विभिन्न स्तरों के लॉक के अंतर्निहित प्रतिच्छेदन के कारण होता है: डेटाबेस लॉक (Room), SharedPreferences लॉक, और मेमोरी में कलेक्शन लॉक। इनमें से प्रत्येक लॉक विभिन्न घटकों द्वारा प्रबंधित किया जाता है, और अधिग्रहण क्रम के लिए केंद्रीकृत प्रोटोकॉल के बिना, डेवलपर्स अनजाने में चक्र बना देते हैं।
आइए आपसी ब्लॉकिंग का एक क्लासिक उदाहरण देखें — दो थ्रेड अलग-अलग क्रम में लॉक प्राप्त करते हैं। यदि पहला थ्रेड संसाधन A को लॉक करता है और B प्राप्त करने का प्रयास करता है, और दूसरा B को लॉक करता है और A प्राप्त करने का प्रयास करता है, तो Deadlock होता है।
class DeadlockExample {
private val lockA = Any()
private val lockB = Any()
fun operationA() {
synchronized(lockA) {
Thread.sleep(50) // कार्य सिमुलेशन
synchronized(lockB) {
println("operationA पूर्ण हुआ")
}
}
}
fun operationB() {
synchronized(lockB) { // उल्टा क्रम
Thread.sleep(50)
synchronized(lockA) {
println("operationB पूर्ण हुआ")
}
}
}
}
fun main() {
val ex = DeadlockExample()
Thread { ex.operationA() }.start()
Thread { ex.operationB() }.start()
// एप्लिकेशन हमेशा के लिए हैंग हो जाएगा — Deadlock!
}
इस उदाहरण में, operationA lockA प्राप्त करता है, और operationB lockB प्राप्त करता है। फिर प्रत्येक दूसरा लॉक प्राप्त करने का प्रयास करता है — और दोनों अनिश्चित काल तक प्रतीक्षा करते हैं। प्रोग्राम बिना त्रुटि संदेश के हैंग हो जाता है। इसे ठीक करने का एकमात्र तरीका सभी विधियों में लॉक अधिग्रहण के समान क्रम की गारंटी देना है।
इन तीन concurrency समस्याओं को अक्सर भ्रमित किया जाता है, लेकिन उनके तंत्र और परिणाम मौलिक रूप से भिन्न हैं। Deadlock — पूर्ण विराम, Starvation — संसाधन की अनंत प्रतीक्षा, Livelock — सक्रिय निष्क्रियता। सही समाधान रणनीति चुनने के लिए अंतर को समझना महत्वपूर्ण है।
| विशेषता | Deadlock | Starvation | Livelock |
|---|---|---|---|
| थ्रेड की स्थिति | अवरुद्ध (BLOCKED) | तैयार (RUNNABLE) | सक्रिय (RUNNABLE) |
| कार्य निष्पादन | नहीं | नहीं | हाँ, लेकिन बेकार |
| कारण | चक्रीय प्रतीक्षा | अनुचित शेड्यूलिंग | गलत संघर्ष प्रबंधन |
| पता लगाना | Thread Dump, टाइमआउट | प्रगति निगरानी | पुनः प्रयास काउंटर |
Starvation (भुखमरी) तब होती है जब शेड्यूलर दूसरों के पक्ष में कम प्राथमिकता वाले थ्रेड के निष्पादन को लगातार स्थगित करता है। Deadlock के विपरीत, थ्रेड अवरुद्ध नहीं है — वह निष्पादन के लिए तैयार है लेकिन CPU समय प्राप्त नहीं करता। Android में, एक विशिष्ट परिदृश्य कम प्राथमिकता वाला बैकग्राउंड थ्रेड है जो कभी निष्पादित नहीं होता यदि UI थ्रेड और Service थ्रेड लगातार सक्रिय हैं।
Livelock (सक्रिय ब्लॉकिंग) एक ऐसी स्थिति है जहां थ्रेड अवरुद्ध नहीं हैं लेकिन एक दूसरे की क्रियाओं पर अंतहीन प्रतिक्रिया करते हैं बिना उपयोगी कार्य किए। क्लासिक उदाहरण — दो लोग गलियारे में मिलते हैं और दोनों रास्ता देने की कोशिश करते हैं, एक ही दिशा में चलते हैं। Deadlock के विपरीत, Livelock में थ्रेड CPU की खपत करते हैं, डिवाइस की बैटरी खत्म करते हैं।
Thread Dump JVM और Android Runtime में आपसी ब्लॉकिंग का पता लगाने का प्राथमिक उपकरण है। डंप के दौरान, JVM स्वचालित रूप से मॉनिटर के बीच निर्भरता ग्राफ का विश्लेषण करता है और Deadlock चक्रों को चिह्नित करता है। Android Studio में, थ्रेड डंप Android Profiler या ADB Shell से kill -3 PID कमांड के माध्यम से प्राप्त किया जा सकता है।
रनटाइम पर स्वचालित Deadlock डिटेक्शन Watchdog टाइमर के माध्यम से कार्यान्वित किया जाता है। यदि कोई थ्रेड निर्दिष्ट टाइमआउट के भीतर कोई ऑपरेशन पूरा नहीं करता है, तो watchdog डंप शुरू करता है और Crash Reporting सिस्टम (Firebase Crashlytics, Sentry) को रिपोर्ट भेजता है। Sentry (Issue Resolution Report, 2024) के अनुसार, watchdog कॉन्फ़िगर करने से Deadlock निदान समय हफ्तों से कुछ घंटों तक कम हो जाता है।
डेवलपमेंट चरण में, JetBrains का ThreadSafe स्थैतिक विश्लेषक और Lock Checker मॉड्यूल के साथ Checker Framework प्रभावी हैं। ये उपकरण स्रोत कोड स्तर पर लॉक अधिग्रहण के क्रम का विश्लेषण करते हैं और संभावित चक्रों के बारे में चेतावनी देते हैं। इसके अतिरिक्त, Test-Driven Deadlock Detection की सिफारिश की जाती है — स्ट्रेस टेस्ट जो सैकड़ों थ्रेड में विभिन्न लॉक क्रमों के साथ संचालन चलाते हैं।
विशेष ध्यान Cooperative Deadlock Detection का है — एक विधि जहां थ्रेड वैश्विक रजिस्ट्री के माध्यम से प्राप्त लॉक के बारे में जानकारी का आदान-प्रदान करते हैं। यदि कोई थ्रेड संभावित चक्र का पता लगाता है, तो वह सभी संसाधन जारी करता है और ऑपरेशन दोहराता है। यह दृष्टिकोण वितरित सिस्टम (Apache ZooKeeper, Google Chubby) में उपयोग किया जाता है और Jetpack Sync जैसी लाइब्रेरी के माध्यम से धीरे-धीरे मोबाइल डेवलपमेंट में अपनाया जा रहा है।
सबसे विश्वसनीय तरीका पूरे एप्लिकेशन में लॉक अधिग्रहण का वैश्विक क्रम स्थापित करना है। यदि सभी थ्रेड हमेशा पहले छोटी संख्या वाला लॉक प्राप्त करते हैं, फिर बड़ी संख्या वाला, तो चक्रीय प्रतीक्षा (Circular Wait शर्त) असंभव है। बड़े प्रोजेक्ट में, क्रम दस्तावेजित किया जाता है और कोड समीक्षा के माध्यम से सत्यापित किया जाता है।
TryLock एक लॉकिंग विधि है जो थ्रेड को अनिश्चित काल तक ब्लॉक नहीं करती, बल्कि निर्दिष्ट समय के भीतर लॉक प्राप्त न होने पर false लौटाती है। Java में, यह ReentrantLock.tryLock(timeout, TimeUnit) के माध्यम से कार्यान्वित किया जाता है, Kotlin Coroutines में — टाइमआउट के साथ Mutex.withLock के माध्यम से। विफलता पर, थ्रेड सभी प्राप्त संसाधन जारी करता है और बाद में पुनः प्रयास करता है।
बैंकर एल्गोरिदम Edsger Dijkstra द्वारा प्रस्तावित Deadlock रोकथाम की एक सैद्धांतिक विधि है। यह संसाधन आवंटन को बैंक लेनदेन के रूप में मॉडल करता है: सिस्टम कोई संसाधन आवंटित नहीं करता यदि यह असुरक्षित स्थिति (deadlock) का कारण बन सकता है। व्यवहार में, थ्रेड की अधिकतम आवश्यकताओं को पहले से जानने की कठिनाई के कारण एल्गोरिदम शायद ही कभी मोबाइल डेवलपमेंट में उपयोग किया जाता है, लेकिन इसके सिद्धांत SQLite डेटाबेस और फ़ाइल सिस्टम में उपयोग किए जाते हैं।
अक्सर पूछे जाने वाले प्रश्न
नहीं, आपसी ब्लॉकिंग के लिए कम से कम दो थ्रेड आवश्यक हैं। एकल-थ्रेडेड कोड में, सभी ऑपरेशन अनुक्रमिक रूप से निष्पादित होते हैं, इसलिए चक्रीय प्रतीक्षा असंभव है। हालांकि, फ़ाइल लॉक या इंटरप्रोसेस सेमाफोर का उपयोग करते समय Deadlock प्रक्रियाओं के बीच हो सकता है।
Coroutines में, Deadlock सस्पेंड फ़ंक्शन (suspend) के स्तर पर होता है और OS थ्रेड को ब्लॉक नहीं करता, जिससे यह कम ध्यान देने योग्य होता है। kotlinx.coroutines का Mutex एक सस्पेंडिंग लॉक है — यह थ्रेड को ब्लॉक नहीं करता, लेकिन coroutine निष्पादित नहीं होता। पता लगाने के लिए, kotlinx-coroutines-debug मॉड्यूल से DebugProbes का उपयोग करें।
SQLite Deadlock तब होता है जब डेटाबेस के दो कनेक्शन अलग-अलग क्रम में लेनदेन निष्पादित करने का प्रयास करते हैं। SQLite ऐसी स्थितियों का पता लगाता है और SQLITE_BUSY या SQLITE_LOCKED त्रुटि कोड लौटाता है। Android में, एकल डेटाबेस इंस्टेंस और @Transaction के माध्यम से लेनदेन के साथ Room का उपयोग करने की सिफारिश की जाती है, जो अंतर-कनेक्शन Deadlock को समाप्त करता है।
Android Runtime में एक अंतर्निहित Deadlock डिटेक्टर है जो ANR (Application Not Responding) उत्पन्न होने पर चलता है। सिस्टम एप्लिकेशन के सभी थ्रेड के Thread Dump का विश्लेषण करता है और आपसी ब्लॉकिंग को चिह्नित करता है। परिणाम /data/anr/traces.txt और Google Play Console के ANR Reports अनुभाग में उपलब्ध है।
सबसे पहले, एप्लिकेशन के सभी थ्रेड का Thread Dump प्राप्त करें। विश्लेषण करें कि प्रत्येक थ्रेड कौन से लॉक रखता है और कौन से प्राप्त करने का प्रयास कर रहा है। समय सीमा पार होने पर स्वचालित डंप के साथ Watchdog टाइमर लागू करें। ठीक करने के बाद, पुनरावृत्ति को रोकने के लिए CI पाइपलाइन में ThreadSafety lint नियम जोड़ें।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें