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 থেকে করুটিন এবং Mutex পছন্দনীয়, যা থ্রেড ব্লক করার পরিবর্তে করুটিনকে সাসপেন্ড করে।

iOS (Swift) এ লক

iOS-এ, স্ট্যান্ডার্ড NSLock কম ব্যবহৃত হয় — ডেভেলপাররা ব্যারিয়ার ফ্ল্যাগ সহ DispatchQueue বা os_unfair_lock পছন্দ করেন। Swift 5.7+ actors-এর মাধ্যমে আধুনিক সিঙ্ক্রোনাইজেশন মেকানিজম প্রদান করে, যা স্বয়ংক্রিয়ভাবে অবস্থা রক্ষা করে।

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-এ lock। ক্রিটিক্যাল সেকশন সফলভাবে সম্পন্ন হোক বা ব্যতিক্রম নিক্ষেপ করুক না কেন, লকটি অবশ্যই মুক্তি দিতে হবে। এটি নিশ্চিত করে যে একটি ত্রুটির কারণে অন্যান্য থ্রেড চিরতরে ব্লক না হয়। 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 নির্বাচন করবেন?

করুটিন সহ Android-এর জন্য, kotlinx.coroutines থেকে Mutex ব্যবহার করুন — এটি থ্রেড ব্লক করার পরিবর্তে করুটিনকে সাসপেন্ড করে। Swift 5.7+ সহ iOS-এর জন্য, actors পছন্দনীয় যা স্বয়ংক্রিয়ভাবে অবস্থা অ্যাক্সেস সিঙ্ক্রোনাইজ করে। ReentrantLock লিগেসি কোড এবং নিম্ন-স্তরের পরিস্থিতির জন্য সংরক্ষিত রাখুন।

সারাংশ

  • Lock java.util.concurrent.locks থেকে একটি স্পষ্ট লক ব্যবস্থাপনা ইন্টারফেস।
  • ReentrantLock পুনরায় অধিগ্রহণ এবং ন্যায্যতার সমর্থন সহ প্রধান বাস্তবায়ন।
  • ReadWriteLock রিড-হেভি পরিস্থিতির জন্য রিড এবং রাইট লক আলাদা করে।
  • StampedLock সর্বোচ্চ পারফরম্যান্সের জন্য অপ্টিমিস্টিক রিডিং যুক্ত করে।
  • টাইমআউট এবং Conditions Lock-এর synchronized-এর উপর মূল সুবিধা।
  • Deadlock সামঞ্জস্যপূর্ণ লক ক্রম এবং tryLock ব্যবহার করে প্রতিরোধ করা হয়।
  • মোবাইল ডেভেলপমেন্টে, করুটিন (Android) এবং actors (iOS) সুপারিশ করা হয়।

আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব

IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।

প্রকল্প নিয়ে আলোচনা করুন

আরও পড়ুন