CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-kotlinx--atomicfu-jvm

AtomicFU JVM-specific artifact providing idiomatic and efficient atomic operations optimized for the JVM platform using AtomicXxxFieldUpdater or VarHandle.

Pending
Overview
Eval results
Files

locks.mddocs/

Locks and Synchronization

Multiplatform synchronization primitives including reentrant locks and synchronized blocks, providing thread-safe coordination mechanisms for complex concurrent operations.

Capabilities

Reentrant Lock Factory

Creates reentrant locks for advanced synchronization scenarios requiring explicit lock management.

/**
 * Creates a new ReentrantLock instance.
 * On JVM, this is a typealias for java.util.concurrent.locks.ReentrantLock.
 * @returns New ReentrantLock instance
 */
fun reentrantLock(): ReentrantLock

/**
 * JVM typealias for java.util.concurrent.locks.ReentrantLock
 */
typealias ReentrantLock = java.util.concurrent.locks.ReentrantLock

Usage Examples:

import kotlinx.atomicfu.locks.*

class ConcurrentResourceManager {
    private val lock = reentrantLock()
    private val resources = mutableMapOf<String, Any>()
    
    fun addResource(key: String, resource: Any) {
        lock.lock()
        try {
            resources[key] = resource
            println("Added resource: $key")
        } finally {
            lock.unlock()
        }
    }
    
    fun getResource(key: String): Any? {
        lock.lock()
        try {
            return resources[key]
        } finally {
            lock.unlock()
        }
    }
    
    fun removeResource(key: String): Any? {
        lock.lock()
        try {
            return resources.remove(key)
        } finally {
            lock.unlock()
        }
    }
    
    fun getAllKeys(): Set<String> {
        lock.lock()
        try {
            return resources.keys.toSet()
        } finally {
            lock.unlock()
        }
    }
}

ReentrantLock with Lock Extension

Convenient extension function for automatic lock management with proper cleanup.

/**
 * Executes the given block while holding the lock, automatically releasing it afterwards.
 * @param block - Code block to execute while holding the lock
 * @returns Result of the block execution
 */
fun <T> ReentrantLock.withLock(block: () -> T): T

Usage Examples:

import kotlinx.atomicfu.locks.*

class ThreadSafeCounter {
    private val lock = reentrantLock()
    private var count = 0
    
    fun increment(): Int = lock.withLock {
        count++
        count
    }
    
    fun decrement(): Int = lock.withLock {
        count--
        count
    }
    
    fun get(): Int = lock.withLock { count }
    
    fun addAndGet(delta: Int): Int = lock.withLock {
        count += delta
        count
    }
    
    fun reset(): Int = lock.withLock {
        val oldValue = count
        count = 0
        oldValue
    }
}

// Complex example with multiple operations
class BankAccount(private val initialBalance: Double) {
    private val lock = reentrantLock()
    private var balance = initialBalance
    private val transactions = mutableListOf<String>()
    
    fun deposit(amount: Double): Double = lock.withLock {
        require(amount > 0) { "Deposit amount must be positive" }
        balance += amount
        transactions.add("Deposit: +$amount")
        balance
    }
    
    fun withdraw(amount: Double): Double = lock.withLock {
        require(amount > 0) { "Withdrawal amount must be positive" }
        require(balance >= amount) { "Insufficient funds" }
        balance -= amount
        transactions.add("Withdrawal: -$amount")
        balance
    }
    
    fun getBalance(): Double = lock.withLock { balance }
    
    fun getTransactionHistory(): List<String> = lock.withLock {
        transactions.toList() // Return defensive copy
    }
    
    fun transfer(other: BankAccount, amount: Double): Boolean {
        // Avoid deadlock by ordering locks by object hash
        val (firstLock, secondLock) = if (this.hashCode() < other.hashCode()) {
            this.lock to other.lock
        } else {
            other.lock to this.lock
        }
        
        return firstLock.withLock {
            secondLock.withLock {
                if (this.balance >= amount) {
                    this.balance -= amount
                    other.balance += amount
                    this.transactions.add("Transfer out: -$amount")
                    other.transactions.add("Transfer in: +$amount")
                    true
                } else {
                    false
                }
            }
        }
    }
}

Synchronized Object

Platform-specific synchronization object for use with synchronized blocks.

/**
 * JVM typealias for Any - any object can be used for synchronization
 */
typealias SynchronizedObject = Any

/**
 * Executes the given block synchronized on the specified lock object.
 * @param lock - Object to synchronize on
 * @param block - Code block to execute synchronized
 * @returns Result of the block execution
 */
fun <T> synchronized(lock: SynchronizedObject, block: () -> T): T

Usage Examples:

import kotlinx.atomicfu.locks.*

class SynchronizedDataStore {
    private val lock = Any() // SynchronizedObject
    private val data = mutableMapOf<String, String>()
    
    fun put(key: String, value: String) = synchronized(lock) {
        data[key] = value
    }
    
    fun get(key: String): String? = synchronized(lock) {
        data[key]
    }
    
    fun remove(key: String): String? = synchronized(lock) {
        data.remove(key)
    }
    
    fun size(): Int = synchronized(lock) {
        data.size
    }
    
    fun getAllEntries(): Map<String, String> = synchronized(lock) {
        data.toMap() // Return defensive copy
    }
    
    fun clear() = synchronized(lock) {
        data.clear()
    }
}

// Multiple synchronized objects for fine-grained locking
class MultiLockCache {
    private val readLock = Any()
    private val writeLock = Any()
    private val cache = mutableMapOf<String, Any>()
    private var cacheStats = mutableMapOf<String, Int>()
    
    fun get(key: String): Any? = synchronized(readLock) {
        val value = cache[key]
        if (value != null) {
            synchronized(writeLock) {
                cacheStats[key] = (cacheStats[key] ?: 0) + 1
            }
        }
        value
    }
    
    fun put(key: String, value: Any) = synchronized(writeLock) {
        cache[key] = value
        cacheStats[key] = cacheStats[key] ?: 0
    }
    
    fun getStats(): Map<String, Int> = synchronized(writeLock) {
        cacheStats.toMap()
    }
}

ReentrantLock Core Operations

Direct access to ReentrantLock methods for advanced use cases.

class ReentrantLock {
    /** Acquires the lock, blocking if necessary */
    fun lock()
    
    /** Attempts to acquire the lock without blocking */
    fun tryLock(): Boolean
    
    /** Releases the lock */
    fun unlock()
}

Usage Examples:

import kotlinx.atomicfu.locks.*
import java.util.concurrent.TimeUnit

class AdvancedLockExample {
    private val lock = reentrantLock()
    private var sharedResource: String? = null
    
    fun tryUpdateResource(newValue: String, timeoutMs: Long): Boolean {
        val acquired = lock.tryLock(timeoutMs, TimeUnit.MILLISECONDS)
        if (!acquired) {
            println("Failed to acquire lock within timeout")
            return false
        }
        
        try {
            // Simulate some work
            Thread.sleep(100)
            sharedResource = newValue
            println("Resource updated to: $newValue")
            return true
        } finally {
            lock.unlock()
        }
    }
    
    fun getResourceWithTimeout(timeoutMs: Long): String? {
        val acquired = lock.tryLock(timeoutMs, TimeUnit.MILLISECONDS)
        if (!acquired) {
            println("Failed to acquire lock for reading")
            return null
        }
        
        try {
            return sharedResource
        } finally {
            lock.unlock()
        }
    }
    
    fun forceUpdateResource(newValue: String) {
        lock.lock() // Block until lock is available
        try {
            sharedResource = newValue
            println("Resource force-updated to: $newValue")
        } finally {
            lock.unlock()
        }
    }
}

Advanced Synchronization Patterns

Reader-Writer Lock Pattern

Using multiple locks for reader-writer scenarios:

import kotlinx.atomicfu.locks.*
import kotlinx.atomicfu.*

class ReadWriteCache<K, V> {
    private val readLock = reentrantLock()
    private val writeLock = reentrantLock()
    private val cache = mutableMapOf<K, V>()
    private val readers = atomic(0)
    
    fun read(key: K): V? {
        readLock.withLock {
            readers.incrementAndGet()
        }
        
        try {
            return cache[key]
        } finally {
            readLock.withLock {
                readers.decrementAndGet()
            }
        }
    }
    
    fun write(key: K, value: V) {
        writeLock.withLock {
            // Wait for all readers to finish
            while (readers.value > 0) {
                Thread.yield()
            }
            
            cache[key] = value
        }
    }
    
    fun size(): Int = readLock.withLock { cache.size }
}

Condition-based Synchronization

Using locks with condition variables:

import kotlinx.atomicfu.locks.*
import kotlinx.atomicfu.*
import java.util.concurrent.locks.Condition

class BlockingQueue<T>(private val capacity: Int) {
    private val lock = reentrantLock()
    private val notFull: Condition = lock.newCondition()
    private val notEmpty: Condition = lock.newCondition()
    private val queue = ArrayDeque<T>()
    
    fun put(item: T) = lock.withLock {
        while (queue.size >= capacity) {
            notFull.await()
        }
        queue.addLast(item)
        notEmpty.signal()
    }
    
    fun take(): T = lock.withLock {
        while (queue.isEmpty()) {
            notEmpty.await()
        }
        val item = queue.removeFirst()
        notFull.signal()
        item
    }
    
    fun size(): Int = lock.withLock { queue.size }
    
    fun isEmpty(): Boolean = lock.withLock { queue.isEmpty() }
    
    fun isFull(): Boolean = lock.withLock { queue.size >= capacity }
}

Implementation Notes

JVM Integration

  • ReentrantLock is a direct typealias to java.util.concurrent.locks.ReentrantLock
  • SynchronizedObject is a typealias to Any - any object can be used for synchronization
  • synchronized function maps directly to Kotlin's kotlin.synchronized
  • Full compatibility with existing Java concurrent programming patterns

Performance Considerations

  • ReentrantLocks have higher overhead than basic synchronization but offer more features
  • withLock extension provides automatic cleanup and exception safety
  • Synchronized blocks have lower overhead but less flexibility
  • Choose based on specific requirements: simplicity vs. advanced features

Best Practices

  • Always use withLock or proper try/finally blocks for lock management
  • Avoid holding locks for long periods
  • Consider lock ordering to prevent deadlocks in multi-lock scenarios
  • Use tryLock with timeouts for robust error handling
  • Prefer atomic operations over locks when possible for better performance

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-kotlinx--atomicfu-jvm

docs

atomic-arrays.md

atomic-operations.md

index.md

locks.md

thread-parking.md

tracing.md

tile.json