AtomicFU JVM-specific artifact providing idiomatic and efficient atomic operations optimized for the JVM platform using AtomicXxxFieldUpdater or VarHandle.
—
Multiplatform synchronization primitives including reentrant locks and synchronized blocks, providing thread-safe coordination mechanisms for complex concurrent operations.
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.ReentrantLockUsage 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()
}
}
}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): TUsage 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
}
}
}
}
}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): TUsage 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()
}
}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()
}
}
}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 }
}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 }
}ReentrantLock is a direct typealias to java.util.concurrent.locks.ReentrantLockSynchronizedObject is a typealias to Any - any object can be used for synchronizationsynchronized function maps directly to Kotlin's kotlin.synchronizedwithLock extension provides automatic cleanup and exception safetywithLock or proper try/finally blocks for lock managementtryLock with timeouts for robust error handlingInstall with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlinx--atomicfu-jvm