موبائل ڈویلپمنٹ میں Deadlock: یہ کیا ہے، وجوہات اور باہمی بلاکنگ سے بچنے کے طریقے

مصنف: IT Sectr اشاعت: 2026-03-18 مطالعے کا وقت: 10 منٹ

Deadlock (باہمی بلاکنگ) ایک ایسی حالت ہے جس میں دو یا زیادہ تھریڈ دوسرے شرکاء کے پاس موجود وسائل کی رہائی کے لیے لامحدود انتظار کرتے ہیں۔ Oracle Java Tutorials (2024) کے مطابق، Deadlock چکریی انتظار میں پیدا ہوتا ہے جب ہر تھریڈ ایک لاک رکھتا ہے جو دوسرے تھریڈ کو درکار ہے۔ خصوصی پتہ لگانے والے ٹولز کے بغیر، Deadlock بغیر کسی ظاہری غلطی کے ایپلیکیشن کے عمل کو مکمل طور پر روک دیتا ہے۔

اہم نکات

  • Deadlock — تھریڈ کا باہمی بلاک ہونا جہاں ہر تھریڈ دوسرے تھریڈ کے پاس موجود وسائل کا انتظار کرتا ہے
  • Coffman کے چار شرائط (Mutual Exclusion, Hold and Wait, No Preemption, Circular Wait) Deadlock کے وقوع کے لیے ضروری ہیں
  • Deadlock Starvation سے مختلف ہے کیونکہ تھریڈ بلاک نہیں ہوتے بلکہ چکریی انحصار میں فعال طور پر انتظار کرتے ہیں
  • Thread Dump — JVM اور Android Runtime میں Deadlock کا پتہ لگانے کا بنیادی ٹول
  • لاک درجہ بندی اور وسائل کے حصول کا متحدہ ترتیب — باہمی بلاکنگ کو روکنے کا بنیادی طریقہ

Deadlock کیا ہے؟

Deadlock ملٹی تھریڈڈ پروگرامنگ میں ایک ایسی صورت حال ہے جہاں دو یا زیادہ تھریڈ ایک دوسرے کو مستقل طور پر بلاک کر دیتے ہیں۔ ہر تھریڈ دوسرے تھریڈ کے لیے ضروری وسائل رکھتا ہے اور گمشدہ وسائل کے حصول کے انتظار میں اسے جاری نہیں کرتا۔ نتیجتاً، کوئی بھی تھریڈ عمل جاری نہیں رکھ سکتا۔

موبائل ڈویلپمنٹ میں Deadlock خاص طور پر اہم ہے کیونکہ یہ استثناء یا کریش پیدا نہیں کرتا۔ ایپلیکیشن صارف کے اعمال کا جواب دینا بند کر دیتی ہے (ANR — Application Not Responding)، اور واحد راستہ عمل کو زبردستی ختم کرنا ہے۔ Google (Android Performance Patterns، 2023) کے مطابق، Google Play Console میں تقریباً 15% ANR رپورٹس پس منظر کے تھریڈ میں باہمی بلاکنگ سے متعلق ہیں۔

Deadlock اور دیگر ہم وقتی مسائل کے درمیان بنیادی فرق بیرونی مداخلت کے بغیر اس کی ناقابل واپسی ہے۔ تھریڈ خود بخود وسائل جاری نہیں کریں گے کیونکہ آپریٹنگ سسٹم شیڈیولر زبردستی لاک واپس نہیں لے سکتا۔ یہ Deadlock کو Livelock سے ممتاز کرتا ہے، جہاں تھریڈ فعال ہیں لیکن مفید کام نہیں کر رہے۔

Deadlock کے شرائط

1971 میں، Edward G. Coffman نے Deadlock کے وقوع کے لیے ضروری چار لازمی شرائط وضع کیے۔ اگر ان میں سے کم از کم ایک موجود نہ ہو، تو باہمی بلاکنگ ناممکن ہے۔ یہ شرائط Coffman کے شرائط کے نام سے جانے جاتے ہیں اور تمام Deadlock روک تھام الگورتھم کی بنیاد بناتے ہیں۔

باہمی اخراج (Mutual Exclusion)

ایک وسیلہ کسی بھی وقت صرف ایک تھریڈ کے ذریعے حاصل کیا جا سکتا ہے۔ اگر کوئی وسیلہ متعدد تھریڈ کے ذریعے بیک وقت پڑھنے کی اجازت دیتا ہے (مثلاً ReadWriteLock پڑھنے کے موڈ میں)، تو Deadlock نہیں ہوتا۔ یہ شرط Mutex اور لاک کی نوعیت سے پیدا ہوتی ہے۔

پکڑو اور انتظار کرو (Hold and Wait)

ایک تھریڈ پہلے سے حاصل کردہ وسائل کو رکھتا ہے اور ساتھ ہی دوسرے وسائل کے حصول کا انتظار کرتا ہے۔ اگر کوئی تھریڈ اگلے وسائل کی درخواست کرنے سے پہلے موجودہ وسائل کو جاری کر سکتا ہے (دو مرحلہ لاکنگ کے ذریعے)، تو Hold and Wait کی شرط ٹوٹ جاتی ہے۔ Android میں، یہ اکثر اس وقت ظاہر ہوتا ہے جب کوئی تھریڈ ڈیٹا بیس لاک رکھتا ہے اور SharedPreferences لاک حاصل کرنے کی کوشش کرتا ہے۔

جبری بے دخلی نہیں (No Preemption)

آپریٹنگ سسٹم کسی تھریڈ سے زبردستی لاک نہیں لے سکتا۔ وسیلہ صرف اس وقت جاری ہوتا ہے جب تھریڈ خود اسے جاری کرتا ہے۔ کچھ نظاموں میں (مثلاً SQLite WAL موڈ)، انفرادی کارروائیوں کی سطح پر جبری بے دخلی نافذ کی جاتی ہے، جو Deadlock کے خطرے کو کم کرتی ہے۔

چکریی انتظار (Circular Wait)

تھریڈ کی ایک بند زنجیر موجود ہوتی ہے، جن میں سے ہر ایک زنجیر میں اگلے تھریڈ کے پاس موجود وسائل کا انتظار کرتا ہے۔ مثال کے طور پر، تھریڈ A وسائل 1 رکھتا ہے اور وسائل 2 کا انتظار کرتا ہے، تھریڈ B وسائل 2 رکھتا ہے اور وسائل 1 کا انتظار کرتا ہے۔ یہ واحد شرط ہے جسے ڈویلپر ساختی طور پر ختم کر سکتا ہے — لاک درجہ بندی کے ذریعے۔ اگر تمام تھریڈ وسائل کو سختی سے متعین عالمی ترتیب میں حاصل کریں، تو چکر جسمانی طور پر ناممکن ہے۔

عملی طور پر، Android ایپلیکیشنز میں، Deadlock اکثر مختلف سطحوں کے لاک کے مخفی تقاطع کی وجہ سے ہوتا ہے: ڈیٹا بیس لاک (Room)، SharedPreferences لاک، اور میموری میں کلیکشن لاک۔ ان میں سے ہر لاک مختلف اجزاء کے ذریعے منظم کیا جاتا ہے، اور حصول کی ترتیب کے لیے مرکزی پروٹوکول کے بغیر، ڈویلپر غیر ارادی طور پر چکر بنا دیتے ہیں۔

Kotlin میں Deadlock کوڈ کی مثال

باہمی بلاکنگ کی ایک کلاسک مثال دیکھتے ہیں — دو تھریڈ مختلف ترتیب میں لاک حاصل کرتے ہیں۔ اگر پہلا تھریڈ وسائل A کو لاک کرتا ہے اور B حاصل کرنے کی کوشش کرتا ہے، اور دوسرا B کو لاک کرتا ہے اور A حاصل کرنے کی کوشش کرتا ہے، تو Deadlock ہوتا ہے۔

kotlin
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 حاصل کرتا ہے۔ پھر ہر ایک دوسرا لاک حاصل کرنے کی کوشش کرتا ہے — اور دونوں لامحدود انتظار کرتے ہیں۔ پروگرام بغیر کسی غلطی کے پیغام کے پھنس جاتا ہے۔ اسے ٹھیک کرنے کا واحد طریقہ تمام طریقوں میں لاک حصول کی یکساں ترتیب کو یقینی بنانا ہے۔

Deadlock بمقابلہ Starvation بمقابلہ Livelock

ان تینوں ہم وقتی مسائل کو اکثر الجھایا جاتا ہے، لیکن ان کے میکانزم اور نتائج بنیادی طور پر مختلف ہیں۔ Deadlock — مکمل رکاوٹ، Starvation — وسائل کا لامحدود انتظار، Livelock — فعال بے عملی۔ فرق کو سمجھنا صحیح حل کی حکمت عملی منتخب کرنے کے لیے انتہائی اہم ہے۔

خصوصیتDeadlockStarvationLivelock
تھریڈ کی حالتمسدود (BLOCKED)تیار (RUNNABLE)فعال (RUNNABLE)
کام کی انجام دہینہیںنہیںہاں، لیکن بے کار
وجہچکریی انتظارغیر منصفانہ نظام الاوقاتغلط تنازعہ ہینڈلنگ
پتہ لگاناThread Dump، ٹائم آؤٹپیش رفت مانیٹرنگدوبارہ کوشش کاؤنٹر

Starvation (بھوک) اس وقت ہوتی ہے جب شیڈیولر دوسروں کے حق میں کم ترجیحی تھریڈ کی عمل داری کو مسلسل ملتوی کرتا ہے۔ Deadlock کے برعکس، تھریڈ مسدود نہیں ہے — یہ عمل کے لیے تیار ہے لیکن CPU وقت حاصل نہیں کرتا۔ Android میں، ایک عام منظر نامہ کم ترجیحی پس منظر کا تھریڈ ہے جو کبھی عمل نہیں کرتا اگر UI تھریڈ اور Service تھریڈ مسلسل فعال ہوں۔

Livelock (فعال لاک) ایک ایسی صورت حال ہے جہاں تھریڈ مسدود نہیں ہیں لیکن مفید کام کیے بغیر ایک دوسرے کے اعمال پر لامتناہی ردعمل دیتے ہیں۔ کلاسک مثال — دو لوگ راہداری میں ملتے ہیں اور دونوں راستہ دینے کی کوشش کرتے ہیں، ایک ہی سمت میں حرکت کرتے ہیں۔ Deadlock کے برعکس، Livelock میں تھریڈ CPU استعمال کرتے ہیں، ڈیوائس کی بیٹری ختم کرتے ہیں۔

Deadlock کا پتہ کیسے لگائیں

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 جیسی لائبریریوں کے ذریعے آہستہ آہستہ موبائل ڈویلپمنٹ میں اپنایا جا رہا ہے۔

باہمی بلاکنگ روکنے کے طریقے

لاک درجہ بندی (Lock Ordering)

سب سے قابل اعتماد طریقہ پوری ایپلیکیشن میں لاک حصول کی عالمی ترتیب قائم کرنا ہے۔ اگر تمام تھریڈ ہمیشہ پہلے چھوٹے نمبر والا لاک حاصل کریں، پھر بڑے نمبر والا، تو چکریی انتظار (Circular Wait شرط) ناممکن ہے۔ بڑے منصوبوں میں، ترتیب کو دستاویزی شکل دی جاتی ہے اور کوڈ جائزہ کے ذریعے تصدیق کی جاتی ہے۔

ٹائم آؤٹ کے ساتھ TryLock

TryLock ایک لاکنگ طریقہ ہے جو تھریڈ کو لامحدود طور پر بلاک نہیں کرتا بلکہ مخصوص وقت کے اندر لاک حاصل نہ ہونے پر false لوٹاتا ہے۔ Java میں، یہ ReentrantLock.tryLock(timeout, TimeUnit) کے ذریعے، Kotlin Coroutines میں — ٹائم آؤٹ کے ساتھ Mutex.withLock کے ذریعے لاگو کیا جاتا ہے۔ ناکامی پر، تھریڈ تمام حاصل کردہ وسائل جاری کرتا ہے اور بعد میں دوبارہ کوشش کرتا ہے۔

بینکر الگورتھم (Banker's Algorithm)

بینکر الگورتھم Edsger Dijkstra کی طرف سے تجویز کردہ Deadlock روک تھام کا ایک نظریاتی طریقہ ہے۔ یہ وسائل کی تقسیم کو بینک لین دین کے طور پر ماڈل کرتا ہے: نظام کوئی وسیلہ مختص نہیں کرتا اگر یہ غیر محفوظ حالت (deadlock) کا باعث بن سکتا ہے۔ عملی طور پر، تھریڈ کی زیادہ سے زیادہ ضروریات کو پہلے سے جاننے کی دشواری کی وجہ سے الگورتھم شاذ و نادر ہی موبائل ڈویلپمنٹ میں استعمال ہوتا ہے، لیکن اس کے اصول SQLite ڈیٹا بیس اور فائل سسٹم میں استعمال ہوتے ہیں۔

اکثر پوچھے گئے سوالات

کیا ایک تھریڈ والی ایپلیکیشن میں Deadlock ہو سکتا ہے؟

نہیں، باہمی بلاکنگ کے لیے کم از کم دو تھریڈ ضروری ہیں۔ ایک تھریڈ والے کوڈ میں، تمام کارروائیاں ترتیب وار عمل میں آتی ہیں، لہٰذا چکریی انتظار ناممکن ہے۔ تاہم، فائل لاک یا بین العمل سیمفور استعمال کرتے وقت عمل کے درمیان Deadlock ہو سکتا ہے۔

Kotlin Coroutines میں Deadlock تھریڈ میں Deadlock سے کیسے مختلف ہے؟

Coroutines میں، Deadlock معطل افعال (suspend) کی سطح پر ہوتا ہے اور OS تھریڈ کو بلاک نہیں کرتا، جو اسے کم نمایاں بناتا ہے۔ kotlinx.coroutines کا Mutex ایک معطل کرنے والا لاک (suspending) ہے — یہ تھریڈ کو بلاک نہیں کرتا، لیکن coroutine عمل نہیں ہوتا۔ پتہ لگانے کے لیے، kotlinx-coroutines-debug ماڈیول سے DebugProbes استعمال کریں۔

Android پر SQLite میں Deadlock کیا ہے؟

SQLite Deadlock اس وقت ہوتا ہے جب ڈیٹا بیس کے دو کنکشن مختلف ترتیبوں میں لین دین انجام دینے کی کوشش کرتے ہیں۔ SQLite ایسی صورتحال کا پتہ لگاتا ہے اور SQLITE_BUSY یا SQLITE_LOCKED ایرر کوڈ لوٹاتا ہے۔ Android میں، ایک ہی ڈیٹا بیس انسٹینس اور @Transaction کے ذریعے لین دین کے ساتھ Room استعمال کرنے کی سفارش کی جاتی ہے، جو کنکشن کے درمیان Deadlock کو ختم کرتا ہے۔

Android Deadlock کا پتہ کیسے لگاتا ہے؟

Android Runtime میں ایک بلٹ ان Deadlock ڈیٹیکٹر ہے جو ANR (Application Not Responding) پیدا ہونے پر چلتا ہے۔ نظام ایپلیکیشن کے تمام تھریڈ کے Thread Dump کا تجزیہ کرتا ہے اور باہمی بلاکنگ کو نشان زد کرتا ہے۔ نتیجہ /data/anr/traces.txt اور Google Play Console کے ANR Reports سیکشن میں دستیاب ہے۔

پروڈکشن میں Deadlock ملنے پر کیا کریں؟

سب سے پہلے، ایپلیکیشن کے تمام تھریڈ کا Thread Dump حاصل کریں۔ تجزیہ کریں کہ ہر تھریڈ کون سے لاک رکھتا ہے اور کون سے حاصل کرنے کی کوشش کر رہا ہے۔ وقت کی حد سے تجاوز کرنے پر خودکار ڈمپ کے ساتھ Watchdog ٹائمر لاگو کریں۔ اصلاح کے بعد، تکرار کو روکنے کے لیے CI پائپ لائن میں ThreadSafety lint اصول شامل کریں۔

خلاصہ

  • Deadlock — باہمی بلاکنگ جہاں تھریڈ ایک دوسرے کے پاس موجود وسائل کا لامحدود انتظار کرتے ہیں
  • Coffman کے چار شرائط (Mutual Exclusion, Hold and Wait, No Preemption, Circular Wait) Deadlock کے لیے ضروری ہیں
  • Thread Dump — JVM اور Android Runtime میں باہمی بلاکنگ کا پتہ لگانے کا معیاری طریقہ
  • متحدہ عالمی ترتیب کے ساتھ لاک درجہ بندی چکریی انتظار کی شرط کو مکمل طور پر ختم کرتی ہے
  • ٹائم آؤٹ کے ساتھ TryLock لامحدود انتظار کو روکتا ہے اور تھریڈ کو وسائل کی عدم دستیابی کو صحیح طریقے سے سنبھالنے دیتا ہے
  • Deadlock بمقابلہ Starvation — Deadlock میں تھریڈ مسدود ہیں، Starvation میں عمل کے لیے تیار ہیں لیکن CPU نہیں ملتا
  • Watchdog ٹائمر اور جامد تجزیہ کار (ThreadSafe, Checker Framework) — CI/CD میں Deadlock سے بنیادی تحفظ

ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے

IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔

پروجیکٹ پر بحث کریں

مزید پڑھیں