Lock: ano ito, mga uri ng paglock at paggamit sa synchronization

May-akda: IT Sectr Nai-publish: 2026-03-19 Oras ng pagbabasa: 8 min

Ang Lock ay isang mekanismo ng synchronization na nagbibigay ng eksklusibong access sa mga kritikal na seksyon ng code sa mga multithreading na aplikasyon. Ayon sa Oracle, 2024, ang Lock interface ay nagbibigay ng mas nababaluktot na kontrol sa synchronization kumpara sa tradisyonal na mga synchronized block, kabilang ang mga pagtatangka sa paglock na may timeout at suporta para sa maraming pila ng paghihintay.

Mga Pangunahing Punto

  • Lock — interface para sa tahasang pamamahala ng mga paglock sa Java.
  • ReentrantLock — pangunahing implementasyon na may suporta sa muling paglock ng parehong thread.
  • ReadWriteLock naghihiwalay ng mga paglock sa pagbasa at pagsulat para sa mas mataas na pagganap.
  • Deadlock — pangunahing panganib kapag gumagamit ng maraming paglock nang sabay.
  • Hindi tulad ng synchronized, ang Lock ay sumusuporta sa mga timeout at naaantala na paghihintay.

Ano ang Lock?

Lock ay isang interface mula sa paketeng java.util.concurrent.locks na nagbibigay ng tahasang operasyon ng paglock at pag-unlock para sa synchronization ng access sa data. Hindi tulad ng synchronized, ang Lock ay nagbibigay sa developer ng ganap na kontrol sa mekanismo ng paglock.

Kahulugan at papel sa synchronization

Ang Lock interface ay lumitaw sa Java 5 bilang alternatibo sa built-in na synchronized na mekanismo. Ang mga pangunahing metodo ay lock, unlock, tryLock at lockInterruptibly. Ang mga paglock ay nagbibigay-daan sa organisasyon ng ligtas na access sa data sa isang multithreading na kapaligiran, na pumipigil sa mga kondisyon ng race at pagkasira ng data.

Ang pangunahing bentahe ng Lock kumpara sa synchronized ay flexibility. Maaaring subukan ng developer na mag-lock gamit ang timeout, suriin ang pagkakaokupa nito nang hindi nagba-block, o mag-organisa ng maraming pila ng paghihintay na may iba't ibang priyoridad.

Kasaysayan ng pag-unlad

Bago lumitaw ang Lock interface sa Java 5, ang tanging paraan ng synchronization ay synchronized, na nagdusa mula sa mga limitasyon: kakulangan ng mga timeout, imposibilidad na maantala ang paghihintay, at nag-iisang pila. Dinisenyo ni Doug Lea ang paketeng java.util.concurrent, kasama ang Lock bilang pangunahing bloke ng pagtatayo.

Paano gumagana ang paglock?

Paglock ay namamahala ng access sa pamamagitan ng panloob na flag ng estado at pila ng paghihintay. Kapag ang isang thread ay tumawag ng lock(), sinusuri ng mekanismo kung ang paglock ay libre at kung oo ay i-lock ito, o ilalagay ang thread sa pila hanggang sa pag-release.

Atomikong paglock at pag-unlock

Sa puso ng bawat paglock ay isang atomikong operasyon ng paghahambing at pagtatakda (CAS). Sa pagtawag ng lock(), sinusubukan ng thread na atomikong itakda ang flag ng pagkakaokupa. Kung ang flag ay nakatakda na, ang thread ay mai-block. Sa unlock(), ang flag ay ni-reset at isa sa mga naghihintay na thread ay nagising.

kotlin
import java.util.concurrent.locks.ReentrantLock

val lock = ReentrantLock()

fun performTask() {
    lock.lock()
    try {
        // kritikal na seksyon
        println("Gumagana ang thread na ${Thread.currentThread().name}")
    } finally {
        lock.unlock()
    }
}

Pila ng paghihintay at paggising

ReentrantLock ay gumagamit sa loob ng dalawang-daan na pila (CLH lock queue), kung saan ang bawat naghihintay na thread ay kinakatawan ng isang node. Kapag ang paglock ay na-release, ang head node ng pila ay nagising. Ang fair mode ay ginagarantiyahan ang FIFO na pagkakasunod-sunod, habang ang unfair ay nagpapahintulot sa isang bagong thread na mag-lock bago ang mga naghihintay para sa mas mataas na throughput.

Mga pangunahing uri ng paglock

Sa modernong Java stack mayroong ilang mga implementasyon ng mga paglock, bawat isa ay na-optimize para sa mga tiyak na sitwasyon. Ang pagpili ng tamang paglock ay direktang nakakaapekto sa pagganap at pagiging maaasahan ng isang multithreading na aplikasyon.

ReentrantLock

ReentrantLock — ang pangunahing at pinakamadalas na ginagamit na implementasyon ng Lock. Sinusuportahan nito ang muling paglock ng parehong thread: kung ang thread ay mayroon nang paglock, ang paulit-ulit na tawag sa lock() ay hindi ito hinaharangan. Ito ay pumipigil sa deadlock sa mga recursive na tawag.

ReentrantReadWriteLock

Ang ReadWriteLock ay naghihiwalay ng mga paglock sa dalawang mode: pagbasa at pagsulat. Maraming thread ang maaaring sabay na humawak ng paglock sa pagbasa, ngunit ang pagsulat ay nangangailangan ng eksklusibong access. Ito ay makabuluhang nagpapataas ng pagganap sa madalas na pagbasa at bihirang pagsulat.

StampedLock

StampedLock — ang pinakabagong implementasyon, na lumitaw sa Java 8. Sinusuportahan nito ang tatlong mode: pagsulat, pagbasa at optimistikong pagbasa. Ang optimistikong pagbasa ay hindi humahadlang sa ibang mga thread at nagbe-validate ng data pagkatapos ng pagbasa, na nagbibigay ng 10-20% na pagtaas sa pagganap kumpara sa ReadWriteLock.

PaglockJava versionMga modePagganap
ReentrantLockJava 5eksklusibomataas
ReadWriteLockJava 5pagbasa + pagsulatkatamtaman
StampedLockJava 8pagbasa + pagsulat + optimisticnapakataas

ReentrantLock at mga katangian nito

ReentrantLock — ang pinakasikat na implementasyon ng Lock, na nagbibigay ng isang hanay ng mga kakayahan na hindi available sa synchronized. Ang pag-unawa sa mga katangian nito ay kailangan para sa epektibong pagtatrabaho sa multithreading.

Pagkamakatarungan ng paglock (fairness)

Ang constructor ng ReentrantLock ay tumatanggap ng parameter na fair. Kapag true, ginagarantiyahan ng paglock ang FIFO na pagkakasunod-sunod ng access, kapag false ay posible ang paglock ng isang bagong thread bago ang mga naghihintay. Ang patas na mode ay pumipigil sa gutom, ngunit binabawasan ang throughput ng 10-20% dahil sa karagdagang overhead sa pagpapanatili ng pila.

Mga timeout at naaantala na paghihintay

Hindi tulad ng synchronized, ang ReentrantLock ay sumusuporta sa tryLock na may timeout. Kung ang paglock ay hindi nakuha sa loob ng tinukoy na oras, ang thread ay nagpapatuloy sa pag-execute sa halip na mag-block nang walang hanggan. Ang metodo lockInterruptibly ay nagpapahintulot na maantala ang naghihintay na thread sa pamamagitan ng Thread.interrupt().

kotlin
val lock = ReentrantLock()

fun tryTask() {
    if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {
        try {
            println("Nakuha ang paglock")
        } finally {
            lock.unlock()
        }
    } else {
        println("Hindi nakuha ang paglock")
    }
}

Mga Kondisyon (Conditions)

Ang ReentrantLock ay sumusuporta sa maraming variable ng kondisyon sa pamamagitan ng metodong newCondition(). Ang bawat Condition ay may sariling pila ng paghihintay, na nagpapahintulot sa organisasyon ng mga kumplikadong sitwasyon ng paggising. Ang mga metodong await() at signal() ay pumalit sa wait() at notify() mula sa mga synchronized block, ngunit may suporta para sa maraming pila.

ReadWriteLock at StampedLock

ReadWriteLock at StampedLock ay lumulutas ng problema ng pag-optimize ng access kapag ang mga operasyon ng pagbasa ay nangingibabaw sa pagsulat. Ang mga ito ay mas mahusay kaysa sa ReentrantLock sa mga sitwasyon kung saan ang pagbasa ay nangyayari nang mas madalas kaysa sa pagsulat.

ReadWriteLock sa praktika

Ang ReadWriteLock interface ay naglalaman ng dalawang metodo: readLock() at writeLock(). Ang paglock ng pagbasa ay maaaring hawakan ng maraming thread nang sabay, ang paglock ng pagsulat — ng isa lamang. Isang tipikal na halimbawa — isang thread-safe cache: maraming thread ang nagbabasa ng data, at isa lamang ang pana-panahong nag-a-update nito.

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 at optimistikong pagbasa

StampedLock ay nagdaragdag ng ikatlong mode — tryOptimisticRead. Ang mode na ito ay hindi humahadlang sa ibang mga thread, naaalala lamang ang isang stamp ng estado. Pagkatapos ng pagbasa, ang developer ay tumatawag ng validate(stamp) upang suriin kung ang data ay nagbago sa panahon ng pagbasa. Kung nagbago ang data, ang operasyon ay dapat ulitin.

Mga paglock sa mobile development

Sa mga mobile na aplikasyon, ang mga paglock ay ginagamit para sa koordinasyon ng access sa pinagsasaluhang data sa pagitan ng mga thread. Gayunpaman, ang paggamit ng mga ito ay nangangailangan ng espesyal na pag-iingat dahil sa limitadong mapagkukunan ng device at pangangailangan na mapanatili ang pagtugon ng interface.

Mga paglock sa Android (Kotlin)

Sa Android, ang ReentrantLock ay kapaki-pakinabang sa pagtatrabaho sa Room, mga cache at mga file. Mahalagang tandaan: huwag kailanman mag-lock sa pangunahing thread. Para sa asynchronous na code, mas gusto ang mga coroutine at Mutex mula sa kotlinx.coroutines, na hindi humahadlang sa thread kundi nagsususpindi ng coroutine.

Mga paglock sa iOS (Swift)

Sa iOS, ang standard na Lock mula sa NSLock ay mas madalang gamitin — mas gusto ng mga developer ang DispatchQueue na may mga barrier flag o ang mga operational na paglock na os_unfair_lock. Ang Swift 5.7+ ay nagbibigay ng mga modernong mekanismo ng synchronization sa pamamagitan ng actors, na awtomatikong nagpoprotekta ng estado.

swift
import Foundation

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

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

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

Mga rekomendasyon para maiwasan ang deadlock

Upang maiwasan ang deadlock, sundin ang pare-parehong pagkakasunod-sunod ng paglock ng lahat ng paglock sa proyekto. Gamitin ang tryLock na may timeout sa halip na lock() kahit saan kung saan posible ang mahabang pag-block. Isaalang-alang ang paggamit ng Lock-Free algorithm (AtomicReference, ConcurrentHashMap) sa halip ng tradisyonal na mga paglock.

Pinakamahusay na kasanayan sa pagtatrabaho sa Lock

Ang paggamit ng Lock ay nangangailangan ng disiplina at pagsunod sa ilang mga patakaran na pumipigil sa deadlock at pagbaba ng pagganap. Ang mga kasanayang ito ay binuo ng Java community sa loob ng 20 taon ng paggamit ng paketeng java.util.concurrent.

Pag-release sa finally

Ang pinakamahalagang pattern — lock sa finally. Kahit ang kritikal na seksyon ay natapos nang matagumpay o may eksepsyon, ang paglock ay dapat i-release. Ito ay ginagarantiyahan na ang ibang mga thread ay hindi ma-block magpakailanman dahil sa isang pagkakamali. Sa Kotlin, ang pattern na ito ay elegante na nalutas sa pamamagitan ng extension na withLock.

Pag-minimize ng oras ng paghawak

Ang kritikal na seksyon ay dapat na pinakamaikli hangga't maaari. Huwag kailanman magsagawa ng input-output, network request o mahabang pag-compute sa loob ng paglock. Kung kailangan magbasa ng data mula sa server, kunin muna ang mga ito, pagkatapos ay mag-lock lamang para sa pag-update ng pinagsasaluhang estado. Binabawasan nito ang kompetisyon at pinapataas ang throughput ng sistema.

Pare-parehong pagkakasunod-sunod ng paglock

Upang maiwasan ang deadlock sa pagtatrabaho sa maraming Lock, itakda ang global na pagkakasunod-sunod ng paglock sa buong proyekto. Kung unang ni-lock ang lockA, pagkatapos lockB — anumang baligtad na pagkakasunod-sunod ay dapat ipagbawal ng mga patakaran ng code review. Para sa awtomatikong pagsusuri, gumamit ng mga static na analyzer tulad ng SpotBugs at IntelliJ Inspections.

Mga Madalas Itanong

Ano ang pagkakaiba ng Lock at synchronized?

Lock — tahasang interface na may kakayahang timeout at naaantala na paghihintay. synchronized ay awtomatikong naglo-lock at nagre-release ng monitor, ngunit hindi pinapayagan ang paggamit ng tryLock, lockInterruptibly at maraming Condition. Ang Lock ay mas nababaluktot, ngunit nangangailangan ng manu-manong pag-release sa finally.

Ano ang patas na paglock (fair lock)?

Ang patas na paglock ay ginagarantiyahan ang FIFO na pagkakasunod-sunod ng access: ang thread na pinakamatagal na naghihintay ang unang makakakuha ng paglock. Ang hindi patas na paglock ay maaaring magbigay ng access sa isang bagong thread na lumalampas sa pila, na nagpapataas ng throughput ngunit maaaring magdulot ng gutom sa mga naghihintay na thread.

Paano maiwasan ang deadlock gamit ang Lock?

Sundin ang nakapirming pagkakasunod-sunod ng paglock ng lahat ng lock, gamitin ang tryLock na may timeout sa halip ng unconditional lock, at bawasan ang bilang ng sabay na hinahawakang paglock. Ang paggamit ng Lock-Free data structure ay nagbabawas din ng panganib ng deadlock.

Ano ang Condition sa Lock?

Condition — katulad ng wait/notify para sa Lock, na nagpapahintulot sa organisasyon ng maraming independiyenteng pila ng paghihintay. Ang bawat tawag ng newCondition() ay lumilikha ng hiwalay na pila, na nagbibigay ng mas tumpak na kontrol sa paggising ng mga thread kumpara sa nag-iisang pila ng synchronized.

Aling Lock ang pipiliin para sa mobile na aplikasyon?

Para sa Android na may mga coroutine, gamitin ang Mutex mula sa kotlinx.coroutines — ito ay sumususpindi ng coroutine, hindi humahadlang ng thread. Para sa iOS na may Swift 5.7+, mas gusto ang actors, na awtomatikong nag-synchronize ng access sa estado. Iwanan ang ReentrantLock para sa legacy code at low-level na sitwasyon.

Buod

  • Lock — interface ng tahasang pamamahala ng paglock mula sa java.util.concurrent.locks.
  • ReentrantLock — pangunahing implementasyon na may suporta sa muling paglock at pagkamakatarungan.
  • ReadWriteLock naghihiwalay ng mga paglock sa pagbasa at pagsulat para sa read-heavy na sitwasyon.
  • StampedLock nagdaragdag ng optimistikong pagbasa para sa maximum na pagganap.
  • Mga timeout at Condition — pangunahing bentahe ng Lock kumpara sa synchronized.
  • Deadlock ay pinipigilan ng nakapirming pagkakasunod-sunod at paggamit ng tryLock.
  • Sa mobile development inirerekomenda ang mga coroutine (Android) at actors (iOS).

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din