Lock: apa itu, tipe penguncian dan penggunaan dalam sinkronisasi

Penulis: IT Sectr Diterbitkan: 2026-03-19 Waktu membaca: 8 mnt

Lock adalah mekanisme sinkronisasi yang menyediakan akses eksklusif ke bagian kritis kode dalam aplikasi multithreading. Menurut Oracle, 2024, antarmuka Lock memberikan kontrol sinkronisasi yang lebih fleksibel dibandingkan blok synchronized tradisional, termasuk percobaan penguncian dengan timeout dan dukungan untuk beberapa antrian tunggu.

Poin Utama

  • Lock — antarmuka untuk manajemen penguncian eksplisit di Java.
  • ReentrantLock — implementasi dasar dengan dukungan penguncian ulang oleh thread yang sama.
  • ReadWriteLock memisahkan penguncian menjadi baca dan tulis untuk meningkatkan kinerja.
  • Deadlock — risiko utama saat menggunakan beberapa penguncian secara bersamaan.
  • Berbeda dengan synchronized, Lock mendukung timeout dan penantian yang dapat diinterupsi.

Apa itu Lock?

Lock adalah antarmuka dari paket java.util.concurrent.locks yang menyediakan operasi penguncian dan pelepasan eksplisit untuk sinkronisasi akses data. Berbeda dengan synchronized, Lock memberikan pengembang kendali penuh atas mekanisme penguncian.

Definisi dan peran dalam sinkronisasi

Antarmuka Lock muncul di Java 5 sebagai alternatif untuk mekanisme synchronized bawaan. Metode utamanya adalah lock, unlock, tryLock dan lockInterruptibly. Penguncian memungkinkan pengorganisasian akses aman ke data di lingkungan multithreading, mencegah kondisi balapan dan kerusakan data.

Keuntungan utama Lock dibandingkan synchronized adalah fleksibilitas. Pengembang dapat mencoba mengunci dengan timeout, memeriksa status penguncian tanpa memblokir, atau mengatur beberapa antrian tunggu dengan prioritas berbeda.

Sejarah perkembangan

Sebelum munculnya antarmuka Lock di Java 5, satu-satunya cara sinkronisasi adalah synchronized, yang menderita keterbatasan: kurangnya timeout, ketidakmampuan menginterupsi penantian, dan antrian tunggal. Doug Lea merancang paket java.util.concurrent, menyertakan Lock sebagai blok bangunan fundamental.

Bagaimana cara kerja penguncian?

Penguncian mengelola akses melalui bendera status internal dan antrian tunggu. Ketika sebuah thread memanggil lock(), mekanisme memeriksa apakah penguncian bebas dan menguncinya atau menempatkan thread dalam antrian hingga dilepaskan.

Penguncian dan pelepasan atomik

Di dasar setiap penguncian terdapat operasi atomik perbandingan dan pengaturan (CAS). Saat memanggil lock(), thread mencoba mengatur bendera kesibukan secara atomik. Jika bendera sudah diatur, thread akan diblokir. Saat unlock(), bendera direset dan salah satu thread yang menunggu dibangunkan.

kotlin
import java.util.concurrent.locks.ReentrantLock

val lock = ReentrantLock()

fun performTask() {
    lock.lock()
    try {
        // bagian kritis
        println("Thread ${Thread.currentThread().name} bekerja")
    } finally {
        lock.unlock()
    }
}

Antrian tunggu dan pembangunan

ReentrantLock secara internal menggunakan antrian dua arah (CLH lock queue), di mana setiap thread yang menunggu diwakili oleh simpul. Ketika penguncian dilepaskan, simpul kepala antrian dibangunkan. Mode fair (adil) menjamin urutan FIFO, sedangkan unfair memungkinkan penguncian oleh thread baru sebelum yang menunggu untuk meningkatkan throughput.

Jenis utama penguncian

Dalam tumpukan Java modern ada beberapa implementasi penguncian, masing-masing dioptimalkan untuk skenario tertentu. Pemilihan penguncian yang tepat secara langsung mempengaruhi kinerja dan keandalan aplikasi multithreading.

ReentrantLock

ReentrantLock — implementasi dasar dan paling sering digunakan dari Lock. Ini mendukung penguncian ulang oleh thread yang sama: jika thread sudah memiliki penguncian, panggilan lock() berulang tidak memblokirnya. Ini mencegah deadlock pada panggilan rekursif.

ReentrantReadWriteLock

ReadWriteLock memisahkan penguncian menjadi dua mode: baca dan tulis. Beberapa thread dapat secara bersamaan memegang penguncian baca, tetapi menulis memerlukan akses eksklusif. Ini secara signifikan meningkatkan kinerja saat pembacaan sering dan penulisan jarang.

StampedLock

StampedLock — implementasi terbaru, yang muncul di Java 8. Ini mendukung tiga mode: tulis, baca dan baca optimistis. Baca optimistis tidak memblokir thread lain dan memvalidasi data setelah pembacaan, memberikan peningkatan kinerja 10-20% dibandingkan ReadWriteLock.

PenguncianVersi JavaModeKinerja
ReentrantLockJava 5eksklusiftinggi
ReadWriteLockJava 5baca + tulissedang
StampedLockJava 8baca + tulis + optimisticsangat tinggi

ReentrantLock dan fitur-fiturnya

ReentrantLock — implementasi Lock yang paling populer, menyediakan sejumlah kemampuan yang tidak tersedia di synchronized. Memahami fitur-fiturnya diperlukan untuk bekerja efektif dengan multithreading.

Keadilan penguncian (fairness)

Konstruktor ReentrantLock menerima parameter fair. Saat true, penguncian menjamin urutan FIFO akses, saat false, penguncian oleh thread baru sebelum yang menunggu dimungkinkan. Mode adil mencegah kelaparan, tetapi mengurangi throughput sebesar 10-20% karena overhead tambahan untuk memelihara antrian.

Timeout dan penantian yang dapat diinterupsi

Berbeda dengan synchronized, ReentrantLock mendukung tryLock dengan timeout. Jika penguncian tidak dapat diperoleh dalam waktu yang ditentukan, thread melanjutkan eksekusi alih-alih memblokir tanpa batas. Metode lockInterruptibly memungkinkan menginterupsi thread yang menunggu melalui Thread.interrupt().

kotlin
val lock = ReentrantLock()

fun tryTask() {
    if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {
        try {
            println("Penguncian diperoleh")
        } finally {
            lock.unlock()
        }
    } else {
        println("Gagal memperoleh penguncian")
    }
}

Kondisi (Conditions)

ReentrantLock mendukung beberapa variabel kondisi melalui metode newCondition(). Setiap Condition memiliki antrian tunggunya sendiri, memungkinkan pengorganisasian skenario pembangunan yang kompleks. Metode await() dan signal() menggantikan wait() dan notify() dari blok synchronized, tetapi dengan dukungan untuk beberapa antrian.

ReadWriteLock dan StampedLock

ReadWriteLock dan StampedLock memecahkan masalah optimasi akses ketika operasi baca mendominasi tulis. Mereka secara signifikan lebih efisien daripada ReentrantLock dalam skenario di mana pembacaan lebih sering terjadi daripada penulisan.

ReadWriteLock dalam praktik

Antarmuka ReadWriteLock berisi dua metode: readLock() dan writeLock(). Penguncian baca dapat dipegang oleh beberapa thread secara bersamaan, penguncian tulis — hanya oleh satu. Contoh tipikal — cache thread-safe: banyak thread membaca data, dan hanya satu yang secara periodik memperbaruinya.

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 dan baca optimistis

StampedLock menambahkan mode ketiga — tryOptimisticRead. Mode ini tidak memblokir thread lain, hanya mengingat cap (stamp) status. Setelah pembacaan, pengembang memanggil validate(stamp) untuk memeriksa apakah data berubah selama pembacaan. Jika data berubah, operasi harus diulang.

Penguncian dalam pengembangan mobile

Dalam aplikasi mobile, penguncian digunakan untuk koordinasi akses ke data bersama antar thread. Namun, penggunaannya memerlukan kehati-hatian khusus karena sumber daya perangkat yang terbatas dan kebutuhan untuk mempertahankan responsivitas antarmuka.

Penguncian di Android (Kotlin)

Di Android, ReentrantLock berguna saat bekerja dengan Room, cache dan file. Penting untuk diingat: jangan pernah mengunci di thread utama. Untuk kode asinkron, lebih baik menggunakan korutin dan Mutex dari kotlinx.coroutines, yang tidak memblokir thread melainkan menunda korutin.

Penguncian di iOS (Swift)

Di iOS, Lock standar dari NSLock lebih jarang digunakan — pengembang lebih memilih DispatchQueue dengan bendera barrier atau penguncian operasional os_unfair_lock. Swift 5.7+ menyediakan mekanisme sinkronisasi modern melalui actors, yang secara otomatis melindungi status.

swift
import Foundation

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

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

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

Rekomendasi untuk menghindari deadlock

Untuk menghindari deadlock, patuhi urutan penguncian seragam dari semua penguncian dalam proyek. Gunakan tryLock dengan timeout alih-alih lock() di mana pun penguncian jangka panjang mungkin terjadi. Pertimbangkan penerapan algoritma Lock-Free (AtomicReference, ConcurrentHashMap) alih-alih penguncian tradisional.

Praktik terbaik bekerja dengan Lock

Penggunaan Lock memerlukan disiplin dan kepatuhan pada beberapa aturan yang mencegah deadlock dan penurunan kinerja. Praktik-praktik ini dikembangkan oleh komunitas Java selama 20 tahun penggunaan paket java.util.concurrent.

Pelepasan di finally

Pola terpenting — lock di finally. Terlepas dari apakah bagian kritis berhasil atau dengan pengecualian, penguncian harus dilepaskan. Ini menjamin bahwa thread lain tidak akan terblokir selamanya karena satu kesalahan. Di Kotlin, pola ini diselesaikan dengan elegan melalui ekstensi withLock.

Meminimalkan waktu penahanan

Bagian kritis harus maksimal pendek. Jangan pernah melakukan operasi input-output, permintaan jaringan atau perhitungan panjang di dalam penguncian. Jika perlu membaca data dari server, ambil dulu, lalu kunci hanya untuk memperbarui status bersama. Ini mengurangi persaingan dan meningkatkan throughput sistem.

Urutan penguncian seragam

Untuk mencegah deadlock saat bekerja dengan beberapa Lock, tetapkan urutan penguncian global di seluruh proyek. Jika pertama lockA, kemudian lockB — setiap urutan terbalik harus dilarang oleh aturan code review. Untuk pemeriksaan otomatis, gunakan penganalisis statis seperti SpotBugs dan IntelliJ Inspections.

Pertanyaan yang Sering Diajukan

Apa perbedaan antara Lock dan synchronized?

Lock — antarmuka eksplisit dengan kemampuan timeout dan penantian dapat diinterupsi. synchronized secara otomatis mengunci dan melepas monitor, tetapi tidak mengizinkan penggunaan tryLock, lockInterruptibly dan beberapa Condition. Lock lebih fleksibel, tetapi memerlukan pelepasan manual di finally.

Apa itu penguncian adil (fair lock)?

Penguncian adil menjamin urutan FIFO akses: thread yang menunggu paling lama mendapatkan penguncian pertama. Penguncian tidak adil dapat memberikan akses ke thread baru dengan melewati antrian, yang meningkatkan throughput tetapi dapat menyebabkan kelaparan thread yang menunggu.

Bagaimana cara menghindari deadlock saat menggunakan Lock?

Patuhi urutan tetap penguncian semua lock, gunakan tryLock dengan timeout alih-alih lock tanpa syarat, dan minimalkan jumlah penguncian yang dipegang bersamaan. Penerapan struktur data Lock-Free juga mengurangi risiko deadlock.

Apa itu Condition di Lock?

Condition — analog wait/notify untuk Lock, yang memungkinkan pengorganisasian beberapa antrian tunggu independen. Setiap panggilan newCondition() membuat antrian terpisah, memberikan kontrol yang lebih tepat atas pembangunan thread dibandingkan dengan antrian tunggal synchronized.

Lock mana yang harus dipilih untuk aplikasi mobile?

Untuk Android dengan korutin, gunakan Mutex dari kotlinx.coroutines — ini menunda korutin, bukan memblokir thread. Untuk iOS dengan Swift 5.7+, actors lebih disukai, yang secara otomatis menyinkronkan akses ke status. Biarkan ReentrantLock untuk kode lama dan skenario tingkat rendah.

Ringkasan

  • Lock — antarmuka manajemen penguncian eksplisit dari java.util.concurrent.locks.
  • ReentrantLock — implementasi utama dengan dukungan penguncian ulang dan keadilan.
  • ReadWriteLock memisahkan penguncian menjadi baca dan tulis untuk skenario read-heavy.
  • StampedLock menambahkan baca optimistis untuk kinerja maksimal.
  • Timeout dan Condition — keuntungan utama Lock dibandingkan synchronized.
  • Deadlock dicegah dengan urutan penguncian tetap dan penggunaan tryLock.
  • Dalam pengembangan mobile direkomendasikan korutin (Android) dan actors (iOS).

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga