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

atomic-arrays.mddocs/

Atomic Arrays

Array-based atomic data structures for managing collections of atomic values with indexed access patterns.

Capabilities

Atomic Reference Array

Creates arrays of atomic references initialized with null values.

/**
 * Creates array of AtomicRef<T> of specified size, where each element is initialized with null value
 */
fun <T> atomicArrayOfNulls(size: Int): AtomicArray<T?>

class AtomicArray<T> {
    /** Array size property */
    val size: Int
    
    /** Get AtomicRef<T?> at index */
    operator fun get(index: Int): AtomicRef<T?>
}

Usage Examples:

import kotlinx.atomicfu.*

class ConcurrentCache<T> {
    private val cache = atomicArrayOfNulls<T>(100)
    
    fun put(index: Int, value: T) {
        if (index in 0 until cache.size) {
            cache[index].value = value
        }
    }
    
    fun get(index: Int): T? {
        return if (index in 0 until cache.size) {
            cache[index].value
        } else null
    }
    
    fun compareAndSet(index: Int, expected: T?, newValue: T?): Boolean {
        return if (index in 0 until cache.size) {
            cache[index].compareAndSet(expected, newValue)
        } else false
    }
    
    fun clear() {
        for (i in 0 until cache.size) {
            cache[i].value = null
        }
    }
}

Atomic Integer Array

Creates arrays of atomic integers initialized with zero values.

/**
 * Creates a new array of AtomicInt values of the specified size, where each element is initialized with 0
 */
class AtomicIntArray(size: Int) {
    /** Array size property */
    val size: Int
    
    /** Get AtomicInt at index */
    operator fun get(index: Int): AtomicInt
}

Usage Examples:

import kotlinx.atomicfu.*

class ConcurrentCounters {
    private val counters = AtomicIntArray(10)
    
    fun increment(index: Int): Int {
        return if (index in 0 until counters.size) {
            counters[index].incrementAndGet()
        } else 0
    }
    
    fun add(index: Int, delta: Int): Int {
        return if (index in 0 until counters.size) {
            counters[index].addAndGet(delta)
        } else 0
    }
    
    fun get(index: Int): Int {
        return if (index in 0 until counters.size) {
            counters[index].value
        } else 0
    }
    
    fun reset(index: Int) {
        if (index in 0 until counters.size) {
            counters[index].value = 0
        }
    }
    
    fun getTotalCount(): Int {
        var total = 0
        for (i in 0 until counters.size) {
            total += counters[i].value
        }
        return total
    }
}

Atomic Long Array

Creates arrays of atomic longs initialized with zero values.

/**
 * Creates a new array of AtomicLong values of the specified size, where each element is initialized with 0L
 */
class AtomicLongArray(size: Int) {
    /** Array size property */
    val size: Int
    
    /** Get AtomicLong at index */
    operator fun get(index: Int): AtomicLong
}

Usage Examples:

import kotlinx.atomicfu.*

class MetricsCollector {
    private val metrics = AtomicLongArray(50)
    
    fun recordMetric(metricId: Int, value: Long) {
        if (metricId in 0 until metrics.size) {
            metrics[metricId].addAndGet(value)
        }
    }
    
    fun incrementMetric(metricId: Int): Long {
        return if (metricId in 0 until metrics.size) {
            metrics[metricId].incrementAndGet()
        } else 0L
    }
    
    fun getMetric(metricId: Int): Long {
        return if (metricId in 0 until metrics.size) {
            metrics[metricId].value
        } else 0L
    }
    
    fun resetMetric(metricId: Int) {
        if (metricId in 0 until metrics.size) {
            metrics[metricId].value = 0L
        }
    }
    
    fun getSnapshot(): LongArray {
        val snapshot = LongArray(metrics.size)
        for (i in 0 until metrics.size) {
            snapshot[i] = metrics[i].value
        }
        return snapshot
    }
}

Atomic Boolean Array

Creates arrays of atomic booleans initialized with false values.

/**
 * Creates a new array of AtomicBoolean values of the specified size, where each element is initialized with false
 */
class AtomicBooleanArray(size: Int) {
    /** Array size property */
    val size: Int
    
    /** Get AtomicBoolean at index */
    operator fun get(index: Int): AtomicBoolean
}

Usage Examples:

import kotlinx.atomicfu.*

class ConcurrentFlags {
    private val flags = AtomicBooleanArray(32)
    
    fun setFlag(index: Int): Boolean {
        return if (index in 0 until flags.size) {
            flags[index].getAndSet(true)
        } else false
    }
    
    fun clearFlag(index: Int): Boolean {
        return if (index in 0 until flags.size) {
            flags[index].getAndSet(false)
        } else false
    }
    
    fun toggleFlag(index: Int): Boolean {
        if (index in 0 until flags.size) {
            val flag = flags[index]
            while (true) {
                val current = flag.value
                if (flag.compareAndSet(current, !current)) {
                    return !current
                }
            }
        }
        return false
    }
    
    fun isSet(index: Int): Boolean {
        return if (index in 0 until flags.size) {
            flags[index].value
        } else false
    }
    
    fun countSetFlags(): Int {
        var count = 0
        for (i in 0 until flags.size) {
            if (flags[i].value) count++
        }
        return count
    }
    
    fun allSet(): Boolean {
        for (i in 0 until flags.size) {
            if (!flags[i].value) return false
        }
        return true
    }
    
    fun anySet(): Boolean {
        for (i in 0 until flags.size) {
            if (flags[i].value) return true
        }
        return false
    }
}

Advanced Usage Patterns

Lock-Free Data Structures

Atomic arrays are commonly used to build lock-free data structures:

import kotlinx.atomicfu.*

class LockFreeQueue<T>(capacity: Int) {
    private val buffer = atomicArrayOfNulls<T>(capacity)
    private val head = atomic(0)
    private val tail = atomic(0)
    
    fun offer(item: T): Boolean {
        while (true) {
            val currentTail = tail.value
            val nextTail = (currentTail + 1) % buffer.size
            
            if (nextTail == head.value) {
                // Queue is full
                return false
            }
            
            if (buffer[currentTail].compareAndSet(null, item)) {
                tail.compareAndSet(currentTail, nextTail)
                return true
            }
        }
    }
    
    fun poll(): T? {
        while (true) {
            val currentHead = head.value
            val item = buffer[currentHead].value
            
            if (item == null) {
                // Queue is empty
                return null
            }
            
            if (buffer[currentHead].compareAndSet(item, null)) {
                head.compareAndSet(currentHead, (currentHead + 1) % buffer.size)
                return item
            }
        }
    }
}

Parallel Processing with Work Distribution

import kotlinx.atomicfu.*

class WorkDistributor<T>(private val tasks: List<T>) {
    private val processed = AtomicBooleanArray(tasks.size)
    private val results = atomicArrayOfNulls<String>(tasks.size)
    private val nextIndex = atomic(0)
    
    fun getNextTask(): Pair<Int, T>? {
        while (true) {
            val index = nextIndex.value
            if (index >= tasks.size) return null
            
            if (nextIndex.compareAndSet(index, index + 1)) {
                return index to tasks[index]
            }
        }
    }
    
    fun completeTask(index: Int, result: String) {
        results[index].value = result
        processed[index].value = true
    }
    
    fun isComplete(): Boolean {
        for (i in 0 until processed.size) {
            if (!processed[i].value) return false
        }
        return true
    }
    
    fun getResults(): List<String?> {
        return (0 until results.size).map { results[it].value }
    }
}

Implementation Notes

Performance Characteristics

  • Each element in atomic arrays is a separate atomic variable
  • Index access is O(1) but involves atomic operations
  • Memory overhead: each element requires atomic field updater setup
  • Best suited for scenarios with known, fixed-size collections

Thread Safety

  • All operations on individual array elements are atomic
  • Array size is immutable once created
  • Concurrent access to different indices is fully thread-safe
  • Operations on the same index are serialized through atomic operations

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