Lock: یہ کیا ہے، لاک کی اقسام اور سنکرونائزیشن میں استعمال

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

Lock ایک سنکرونائزیشن میکانزم ہے جو ملٹی تھریڈڈ ایپلی کیشنز میں کوڈ کے اہم حصوں تک خصوصی رسائی فراہم کرتا ہے۔ Oracle، 2024 کے مطابق، Lock انٹرفیس روایتی synchronized بلاکس کے مقابلے میں زیادہ لچکدار سنکرونائزیشن کنٹرول فراہم کرتا ہے، جس میں ٹائم آؤٹ کے ساتھ حصول کی کوششیں اور متعدد قطاروں کی معاونت شامل ہے۔

اہم نکات

  • Lock Java میں واضح لاک مینجمنٹ کے لیے ایک انٹرفیس ہے۔
  • ReentrantLock ایک بنیادی نفاذ ہے جو اسی تھریڈ کے ذریعے دوبارہ حصول کی حمایت کرتا ہے۔
  • ReadWriteLock بہتر کارکردگی کے لیے پڑھنے اور لکھنے کے لاک کو الگ کرتا ہے۔
  • Deadlock ایک ساتھ متعدد لاک استعمال کرتے وقت بنیادی خطرہ ہے۔
  • synchronized کے برعکس، Lock ٹائم آؤٹ اور قابل مداخلت انتظار کی حمایت کرتا ہے۔

Lock کیا ہے؟

Lock java.util.concurrent.locks پیکج کا ایک انٹرفیس ہے جو ڈیٹا تک رسائی کو ہم آہنگ کرنے کے لیے واضح لاک اور انلاک آپریشنز فراہم کرتا ہے۔ synchronized کے برعکس، Lock ڈویلپر کو لاکنگ میکانزم پر مکمل کنٹرول دیتا ہے۔

تعریف اور سنکرونائزیشن میں کردار

Lock انٹرفیس Java 5 میں بلٹ ان synchronized میکانزم کے متبادل کے طور پر متعارف کرایا گیا تھا۔ اہم طریقے ہیں lock، unlock، tryLock اور lockInterruptibly۔ لاک ملٹی تھریڈڈ ماحول میں محفوظ ڈیٹا تک رسائی کو منظم کرنے میں مدد کرتے ہیں، ریس کنڈیشن اور ڈیٹا کرپشن کو روکتے ہیں۔

synchronized پر Lock کا بنیادی فائدہ لچک ہے۔ ڈویلپر ٹائم آؤٹ کے ساتھ لاک حاصل کرنے کی کوشش کر سکتا ہے، بغیر بلاک ہوئے اس کی دستیابی چیک کر سکتا ہے، یا مختلف ترجیحات کے ساتھ متعدد قطاریں منظم کر سکتا ہے۔

تاریخ اور ارتقاء

Java 5 میں Lock انٹرفیس آنے سے پہلے، سنکرونائزیشن کا واحد طریقہ synchronized تھا، جو حدود کا شکار تھا: کوئی ٹائم آؤٹ نہیں، کوئی قابل مداخلت انتظار نہیں، اور ایک ہی قطار۔ Doug Lea نے java.util.concurrent پیکج ڈیزائن کیا، جس میں Lock کو بنیادی تعمیراتی بلاک کے طور پر شامل کیا گیا۔

لاک کیسے کام کرتا ہے؟

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

جوہری حصول اور جاری کرنا

کسی بھی لاک کے مرکز میں ایک جوہری موازنہ اور تبادلہ (CAS) آپریشن ہوتا ہے۔ جب lock() کال کیا جاتا ہے، تھریڈ جوہری طور پر مصروف فلیگ سیٹ کرنے کی کوشش کرتا ہے۔ اگر فلیگ پہلے سے سیٹ ہے، تھریڈ بلاک ہو جاتا ہے۔ unlock() پر، فلیگ صاف ہو جاتا ہے اور ایک منتظر تھریڈ جاگ جاتا ہے۔

kotlin
import java.util.concurrent.locks.ReentrantLock

val lock = ReentrantLock()

fun performTask() {
    lock.lock()
    try {
        // اہم حصہ
        println("تھریڈ ${Thread.currentThread().name} کام کر رہا ہے")
    } finally {
        lock.unlock()
    }
}

قطار اور بیداری

ReentrantLock اندرونی طور پر ایک دو طرفہ منسلک فہرست (CLH لاک قطار) استعمال کرتا ہے جہاں ہر منتظر تھریڈ کو ایک نوڈ سے ظاہر کیا جاتا ہے۔ جب لاک جاری ہوتا ہے، قطار کا ہیڈ نوڈ بیدار ہوتا ہے۔ منصفانہ موڈ FIFO ترتیب کی ضمانت دیتا ہے، جبکہ غیر منصفانہ موڈ تھروپوٹ بڑھانے کے لیے ایک نئے تھریڈ کو منتظر تھریڈ سے پہلے لاک حاصل کرنے کی اجازت دیتا ہے۔

لاک کی اہم اقسام

جدید Java ماحولیاتی نظام میں، لاک کے متعدد نفاذات ہیں، ہر ایک مخصوص منظرناموں کے لیے بہتر بنایا گیا ہے۔ صحیح لاک کا انتخاب براہ راست ملٹی تھریڈڈ ایپلی کیشن کی کارکردگی اور بھروسے کو متاثر کرتا ہے۔

ReentrantLock

ReentrantLock بنیادی اور سب سے زیادہ استعمال ہونے والا Lock نفاذ ہے۔ یہ اسی تھریڈ کے ذریعے دوبارہ حصول کی حمایت کرتا ہے: اگر کوئی تھریڈ پہلے سے لاک رکھتا ہے، تو lock() کو دوبارہ کال کرنا اسے بلاک نہیں کرتا۔ یہ تکراری کالز میں deadlock کو روکتا ہے۔

ReentrantReadWriteLock

ReadWriteLock لاک کو دو طریقوں میں الگ کرتا ہے: پڑھنا اور لکھنا۔ متعدد تھریڈ ایک ساتھ پڑھنے کا لاک رکھ سکتے ہیں، لیکن لکھنے کے لیے خصوصی رسائی درکار ہے۔ یہ بار بار پڑھنے اور کم لکھنے پر کارکردگی کو نمایاں طور پر بہتر کرتا ہے۔

StampedLock

StampedLock جدید ترین نفاذ ہے، جو Java 8 میں متعارف کرایا گیا۔ یہ تین طریقوں کی حمایت کرتا ہے: لکھنا، پڑھنا اور امیدوارانہ پڑھنا۔ امیدوارانہ پڑھنا دوسرے تھریڈ کو بلاک نہیں کرتا اور پڑھنے کے بعد ڈیٹا کی توثیق کرتا ہے، جو ReadWriteLock کے مقابلے میں 10-20% کارکردگی کا فائدہ فراہم کرتا ہے۔

لاکJava ورژنموڈکارکردگی
ReentrantLockJava 5خصوصیاعلی
ReadWriteLockJava 5پڑھنا + لکھنادرمیانی
StampedLockJava 8پڑھنا + لکھنا + امیدوارانہبہت اعلی

ReentrantLock اور اس کی خصوصیات

ReentrantLock سب سے مقبول Lock نفاذ ہے، جو synchronized میں دستیاب نہ ہونے والی کئی خصوصیات فراہم کرتا ہے۔ اس کی خصوصیات کو سمجھنا مؤثر ملٹی تھریڈنگ کام کے لیے ضروری ہے۔

لاک کی انصاف (fairness)

ReentrantLock کنسٹرکٹر ایک fair پیرامیٹر قبول کرتا ہے۔ جب true ہوتا ہے، لاک FIFO ترتیب کی ضمانت دیتا ہے؛ جب false ہوتا ہے، ایک نیا تھریڈ منتظر تھریڈ سے پہلے لاک حاصل کر سکتا ہے۔ منصفانہ موڈ بھوک کو روکتا ہے لیکن قطار کی دیکھ بھال کے اضافی بوجھ کی وجہ سے تھروپوٹ کو 10-20% کم کرتا ہے۔

ٹائم آؤٹ اور قابل مداخلت انتظار

synchronized کے برعکس، ReentrantLock ٹائم آؤٹ کے ساتھ tryLock کی حمایت کرتا ہے۔ اگر مخصوص وقت میں لاک حاصل نہیں کیا جا سکتا، تھریڈ غیر معینہ مدت تک بلاک ہونے کے بجائے عمل جاری رکھتا ہے۔ lockInterruptibly طریقہ Thread.interrupt() کے ذریعے منتظر تھریڈ میں مداخلت کی اجازت دیتا ہے۔

kotlin
val lock = ReentrantLock()

fun tryTask() {
    if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {
        try {
            println("لاک حاصل ہو گیا")
        } finally {
            lock.unlock()
        }
    } else {
        println("لاک حاصل کرنے میں ناکامی")
    }
}

شرائط (Conditions)

ReentrantLock newCondition() طریقہ کے ذریعے متعدد شرائطی متغیرات کی حمایت کرتا ہے۔ ہر Condition کی اپنی قطار ہوتی ہے، جو پیچیدہ بیداری کے منظرناموں کو قابل بناتی ہے۔ await() اور signal() طریقوں نے synchronized بلاکس کے wait() اور notify() کو بدل دیا، لیکن متعدد قطاروں کی حمایت کے ساتھ۔

ReadWriteLock اور StampedLock

ReadWriteLock اور StampedLock اس رسائی کی اصلاح کو مخاطب کرتے ہیں جب پڑھنا لکھنے پر غالب ہو۔ یہ ان منظرناموں میں ReentrantLock سے نمایاں طور پر زیادہ موثر ہیں جہاں لکھنے کے مقابلے میں پڑھنا زیادہ کثرت سے ہوتا ہے۔

ReadWriteLock عملی طور پر

ReadWriteLock انٹرفیس میں دو طریقے ہیں: readLock() اور writeLock()۔ پڑھنے کا لاک متعدد تھریڈ ایک ساتھ رکھ سکتے ہیں، جبکہ لکھنے کا لاک خصوصی ہے۔ ایک عام مثال تھریڈ سیف کیش ہے: بہت سے تھریڈ ڈیٹا پڑھتے ہیں جبکہ صرف ایک وقتاً فوقتاً اسے اپ ڈیٹ کرتا ہے۔

kotlin
class SafeCache<K, V> {
    private val map = mutableMapOf<K, V>()
    private val rwLock = ReentrantReadWriteLock()

    fun get(key: K): V? {
        rwLock.readLock().lock()
        return try { map[key] } finally { rwLock.readLock().unlock() }
    }

    fun put(key: K, value: V) {
        rwLock.writeLock().lock()
        return try { map[key] = value } finally { rwLock.writeLock().unlock() }
    }
}

StampedLock اور امیدوارانہ پڑھنا

StampedLock تیسرا موڈ شامل کرتا ہے — tryOptimisticRead۔ یہ موڈ دوسرے تھریڈ کو بلاک نہیں کرتا بلکہ صرف حالت کا ایک اسٹیمپ ریکارڈ کرتا ہے۔ پڑھنے کے بعد، ڈویلپر یہ جانچنے کے لیے validate(stamp) کال کرتا ہے کہ پڑھنے کے دوران ڈیٹا تبدیل تو نہیں ہوا۔ اگر ڈیٹا تبدیل ہو گیا، آپریشن دہرایا جانا چاہیے۔

موبائل ڈویلپمنٹ میں لاک

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

Android (Kotlin) میں لاک

Android پر، ReentrantLock Room، کیش اور فائلوں کے ساتھ کام کرتے وقت مفید ہے۔ یاد رکھنا اہم ہے: مین تھریڈ پر کبھی لاک حاصل نہ کریں۔ غیر مطابقت پذیر کوڈ کے لیے، kotlinx.coroutines سے coroutines اور Mutex ترجیح دی جاتی ہیں، جو تھریڈ کو بلاک کرنے کے بجائے coroutine کو معطل کرتے ہیں۔

iOS (Swift) میں لاک

iOS میں، معیاری NSLock کم استعمال ہوتا ہے — ڈویلپر بیریئر فلیگ والی DispatchQueue یا os_unfair_lock کو ترجیح دیتے ہیں۔ Swift 5.7+ ایکٹرز کے ذریعے جدید سنکرونائزیشن میکانزم فراہم کرتا ہے، جو خود بخود حالت کی حفاظت کرتے ہیں۔

swift
import Foundation

actor DataStore {
    private var items: [String] = []

    func add(_ item: String) {
        items.append(item)
    }

    func getAll() -> [String] {
        items
    }
}

ڈیڈلاک سے بچاؤ کی سفارشات

ڈیڈلاک سے بچنے کے لیے، پورے پروجیکٹ میں مستقل لاک ترتیب پر عمل کریں۔ جہاں بھی طویل بلاکنگ ممکن ہو، lock() کے بجائے ٹائم آؤٹ کے ساتھ tryLock استعمال کریں۔ روایتی لاک کے بجائے Lock-Free الگورتھم (AtomicReference، ConcurrentHashMap) استعمال کرنے پر غور کریں۔

Lock کے ساتھ کام کرنے کے بہترین طریقے

Lock کے استعمال کے لیے نظم و ضبط اور کئی اصولوں کی پابندی کی ضرورت ہے جو ڈیڈلاک اور کارکردگی میں کمی کو روکتے ہیں۔ java.util.concurrent پیکج کے 20 سالہ استعمال میں Java کمیونٹی نے یہ طرز عمل تیار کیے ہیں۔

finally میں جاری کرنا

سب سے اہم پیٹرن finally میں لاک جاری کرنا ہے۔ اس سے کوئی فرق نہیں پڑتا کہ اہم حصہ کامیابی سے مکمل ہوتا ہے یا مستثنیٰ پھینکتا ہے، لاک ضرور جاری ہونا چاہیے۔ یہ یقینی بناتا ہے کہ ایک غلطی کی وجہ سے دوسرے تھریڈ ہمیشہ کے لیے بلاک نہ ہوں۔ Kotlin میں، یہ پیٹرن withLock ایکسٹینشن کے ذریعے خوبصورتی سے حل ہوتا ہے۔

ہولڈ ٹائم کو کم سے کم کریں

اہم حصہ جتنا ممکن ہو اتنا چھوٹا ہونا چاہیے۔ لاک کے اندر کبھی بھی I/O، نیٹ ورک درخواستیں یا طویل حساب نہ کریں۔ اگر آپ کو سرور سے ڈیٹا پڑھنے کی ضرورت ہے، پہلے ڈیٹا حاصل کریں، پھر صرف مشترکہ حالت کو اپ ڈیٹ کرنے کے لیے لاک حاصل کریں۔ یہ مسابقت کو کم کرتا ہے اور سسٹم تھروپوٹ کو بہتر بناتا ہے۔

مستقل لاک ترتیب

متعدد لاک کے ساتھ کام کرتے وقت ڈیڈلاک کو روکنے کے لیے، پورے پروجیکٹ میں عالمی لاک ترتیب قائم کریں۔ اگر پہلے lockA حاصل ہوتا ہے، پھر lockB — کسی بھی معکوس ترتیب کو کوڈ ریویو قواعد کے ذریعے ممنوع ہونا چاہیے۔ خودکار تصدیق کے لیے SpotBugs اور IntelliJ Inspections جیسے جامد تجزیہ کار استعمال کریں۔

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

Lock اور synchronized میں کیا فرق ہے؟

Lock ایک واضح انٹرفیس ہے جس میں ٹائم آؤٹ اور قابل مداخلت انتظار کی حمایت ہے۔ synchronized خود بخود مانیٹر حاصل اور جاری کرتا ہے، لیکن tryLock، lockInterruptibly یا متعدد Conditions استعمال کرنے کی اجازت نہیں دیتا۔ Lock زیادہ لچکدار ہے لیکن finally میں دستی جاری کرنے کی ضرورت ہے۔

منصفانہ لاک (fair lock) کیا ہے؟

منصفانہ لاک FIFO ترتیب کی ضمانت دیتا ہے: جو تھریڈ سب سے زیادہ دیر انتظار کر رہا ہے، اسے پہلے لاک ملتا ہے۔ غیر منصفانہ لاک منتظر تھریڈ سے پہلے نئے تھریڈ کو رسائی دے سکتا ہے، جو تھروپوٹ بڑھاتا ہے لیکن منتظر تھریڈ کی بھوک کا سبب بن سکتا ہے۔

Lock استعمال کرتے وقت ڈیڈلاک سے کیسے بچیں؟

تمام لاک حاصل کرنے کے لیے مقررہ ترتیب پر عمل کریں، غیر مشروط lock() کے بجائے ٹائم آؤٹ کے ساتھ tryLock استعمال کریں، اور ایک ساتھ رکھے گئے لاک کی تعداد کم سے کم کریں۔ Lock-Free ڈیٹا ڈھانچے کا استعمال بھی ڈیڈلاک کے خطرے کو کم کرتا ہے۔

Lock میں Condition کیا ہے؟

Condition Lock کے لیے wait/notify کا مشابہ ہے، جو متعدد آزاد قطاروں کی اجازت دیتا ہے۔ ہر newCondition() کال ایک علیحدہ قطار بناتی ہے، جو synchronized کی ایک قطار کے مقابلے میں تھریڈ بیداری پر زیادہ قطعی کنٹرول فراہم کرتی ہے۔

موبائل ایپلی کیشن کے لیے کون سا Lock منتخب کریں؟

coroutines والے Android کے لیے، kotlinx.coroutines سے Mutex استعمال کریں — یہ تھریڈ کو بلاک کرنے کے بجائے coroutine کو معطل کرتا ہے۔ Swift 5.7+ والے iOS کے لیے، ایکٹرز ترجیح دی جاتی ہیں جو خود بخود حالت تک رسائی کو ہم آہنگ کرتے ہیں۔ ReentrantLock کو پرانے کوڈ اور نچلی سطح کے منظرناموں کے لیے چھوڑ دیں۔

خلاصہ

  • Lock java.util.concurrent.locks سے ایک واضح لاک مینجمنٹ انٹرفیس ہے۔
  • ReentrantLock دوبارہ حصول اور انصاف کی حمایت کے ساتھ اہم نفاذ ہے۔
  • ReadWriteLock پڑھنے کے زیادہ منظرناموں کے لیے پڑھنے اور لکھنے کے لاک کو الگ کرتا ہے۔
  • StampedLock زیادہ سے زیادہ کارکردگی کے لیے امیدوارانہ پڑھنا شامل کرتا ہے۔
  • ٹائم آؤٹ اور Conditions Lock کے synchronized پر اہم فوائد ہیں۔
  • Deadlock مستقل لاک ترتیب اور tryLock استعمال سے روکا جاتا ہے۔
  • موبائل ڈویلپمنٹ میں، coroutines (Android) اور ایکٹرز (iOS) تجویز کیے جاتے ہیں۔

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

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

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

مزید پڑھیں