0
# Atomic Arrays
1
2
Array-based atomic data structures for managing collections of atomic values with indexed access patterns.
3
4
## Capabilities
5
6
### Atomic Reference Array
7
8
Creates arrays of atomic references initialized with null values.
9
10
```kotlin { .api }
11
/**
12
* Creates array of AtomicRef<T> of specified size, where each element is initialized with null value
13
*/
14
fun <T> atomicArrayOfNulls(size: Int): AtomicArray<T?>
15
16
class AtomicArray<T> {
17
/** Array size property */
18
val size: Int
19
20
/** Get AtomicRef<T?> at index */
21
operator fun get(index: Int): AtomicRef<T?>
22
}
23
```
24
25
**Usage Examples:**
26
27
```kotlin
28
import kotlinx.atomicfu.*
29
30
class ConcurrentCache<T> {
31
private val cache = atomicArrayOfNulls<T>(100)
32
33
fun put(index: Int, value: T) {
34
if (index in 0 until cache.size) {
35
cache[index].value = value
36
}
37
}
38
39
fun get(index: Int): T? {
40
return if (index in 0 until cache.size) {
41
cache[index].value
42
} else null
43
}
44
45
fun compareAndSet(index: Int, expected: T?, newValue: T?): Boolean {
46
return if (index in 0 until cache.size) {
47
cache[index].compareAndSet(expected, newValue)
48
} else false
49
}
50
51
fun clear() {
52
for (i in 0 until cache.size) {
53
cache[i].value = null
54
}
55
}
56
}
57
```
58
59
### Atomic Integer Array
60
61
Creates arrays of atomic integers initialized with zero values.
62
63
```kotlin { .api }
64
/**
65
* Creates a new array of AtomicInt values of the specified size, where each element is initialized with 0
66
*/
67
class AtomicIntArray(size: Int) {
68
/** Array size property */
69
val size: Int
70
71
/** Get AtomicInt at index */
72
operator fun get(index: Int): AtomicInt
73
}
74
```
75
76
**Usage Examples:**
77
78
```kotlin
79
import kotlinx.atomicfu.*
80
81
class ConcurrentCounters {
82
private val counters = AtomicIntArray(10)
83
84
fun increment(index: Int): Int {
85
return if (index in 0 until counters.size) {
86
counters[index].incrementAndGet()
87
} else 0
88
}
89
90
fun add(index: Int, delta: Int): Int {
91
return if (index in 0 until counters.size) {
92
counters[index].addAndGet(delta)
93
} else 0
94
}
95
96
fun get(index: Int): Int {
97
return if (index in 0 until counters.size) {
98
counters[index].value
99
} else 0
100
}
101
102
fun reset(index: Int) {
103
if (index in 0 until counters.size) {
104
counters[index].value = 0
105
}
106
}
107
108
fun getTotalCount(): Int {
109
var total = 0
110
for (i in 0 until counters.size) {
111
total += counters[i].value
112
}
113
return total
114
}
115
}
116
```
117
118
### Atomic Long Array
119
120
Creates arrays of atomic longs initialized with zero values.
121
122
```kotlin { .api }
123
/**
124
* Creates a new array of AtomicLong values of the specified size, where each element is initialized with 0L
125
*/
126
class AtomicLongArray(size: Int) {
127
/** Array size property */
128
val size: Int
129
130
/** Get AtomicLong at index */
131
operator fun get(index: Int): AtomicLong
132
}
133
```
134
135
**Usage Examples:**
136
137
```kotlin
138
import kotlinx.atomicfu.*
139
140
class MetricsCollector {
141
private val metrics = AtomicLongArray(50)
142
143
fun recordMetric(metricId: Int, value: Long) {
144
if (metricId in 0 until metrics.size) {
145
metrics[metricId].addAndGet(value)
146
}
147
}
148
149
fun incrementMetric(metricId: Int): Long {
150
return if (metricId in 0 until metrics.size) {
151
metrics[metricId].incrementAndGet()
152
} else 0L
153
}
154
155
fun getMetric(metricId: Int): Long {
156
return if (metricId in 0 until metrics.size) {
157
metrics[metricId].value
158
} else 0L
159
}
160
161
fun resetMetric(metricId: Int) {
162
if (metricId in 0 until metrics.size) {
163
metrics[metricId].value = 0L
164
}
165
}
166
167
fun getSnapshot(): LongArray {
168
val snapshot = LongArray(metrics.size)
169
for (i in 0 until metrics.size) {
170
snapshot[i] = metrics[i].value
171
}
172
return snapshot
173
}
174
}
175
```
176
177
### Atomic Boolean Array
178
179
Creates arrays of atomic booleans initialized with false values.
180
181
```kotlin { .api }
182
/**
183
* Creates a new array of AtomicBoolean values of the specified size, where each element is initialized with false
184
*/
185
class AtomicBooleanArray(size: Int) {
186
/** Array size property */
187
val size: Int
188
189
/** Get AtomicBoolean at index */
190
operator fun get(index: Int): AtomicBoolean
191
}
192
```
193
194
**Usage Examples:**
195
196
```kotlin
197
import kotlinx.atomicfu.*
198
199
class ConcurrentFlags {
200
private val flags = AtomicBooleanArray(32)
201
202
fun setFlag(index: Int): Boolean {
203
return if (index in 0 until flags.size) {
204
flags[index].getAndSet(true)
205
} else false
206
}
207
208
fun clearFlag(index: Int): Boolean {
209
return if (index in 0 until flags.size) {
210
flags[index].getAndSet(false)
211
} else false
212
}
213
214
fun toggleFlag(index: Int): Boolean {
215
if (index in 0 until flags.size) {
216
val flag = flags[index]
217
while (true) {
218
val current = flag.value
219
if (flag.compareAndSet(current, !current)) {
220
return !current
221
}
222
}
223
}
224
return false
225
}
226
227
fun isSet(index: Int): Boolean {
228
return if (index in 0 until flags.size) {
229
flags[index].value
230
} else false
231
}
232
233
fun countSetFlags(): Int {
234
var count = 0
235
for (i in 0 until flags.size) {
236
if (flags[i].value) count++
237
}
238
return count
239
}
240
241
fun allSet(): Boolean {
242
for (i in 0 until flags.size) {
243
if (!flags[i].value) return false
244
}
245
return true
246
}
247
248
fun anySet(): Boolean {
249
for (i in 0 until flags.size) {
250
if (flags[i].value) return true
251
}
252
return false
253
}
254
}
255
```
256
257
## Advanced Usage Patterns
258
259
### Lock-Free Data Structures
260
261
Atomic arrays are commonly used to build lock-free data structures:
262
263
```kotlin
264
import kotlinx.atomicfu.*
265
266
class LockFreeQueue<T>(capacity: Int) {
267
private val buffer = atomicArrayOfNulls<T>(capacity)
268
private val head = atomic(0)
269
private val tail = atomic(0)
270
271
fun offer(item: T): Boolean {
272
while (true) {
273
val currentTail = tail.value
274
val nextTail = (currentTail + 1) % buffer.size
275
276
if (nextTail == head.value) {
277
// Queue is full
278
return false
279
}
280
281
if (buffer[currentTail].compareAndSet(null, item)) {
282
tail.compareAndSet(currentTail, nextTail)
283
return true
284
}
285
}
286
}
287
288
fun poll(): T? {
289
while (true) {
290
val currentHead = head.value
291
val item = buffer[currentHead].value
292
293
if (item == null) {
294
// Queue is empty
295
return null
296
}
297
298
if (buffer[currentHead].compareAndSet(item, null)) {
299
head.compareAndSet(currentHead, (currentHead + 1) % buffer.size)
300
return item
301
}
302
}
303
}
304
}
305
```
306
307
### Parallel Processing with Work Distribution
308
309
```kotlin
310
import kotlinx.atomicfu.*
311
312
class WorkDistributor<T>(private val tasks: List<T>) {
313
private val processed = AtomicBooleanArray(tasks.size)
314
private val results = atomicArrayOfNulls<String>(tasks.size)
315
private val nextIndex = atomic(0)
316
317
fun getNextTask(): Pair<Int, T>? {
318
while (true) {
319
val index = nextIndex.value
320
if (index >= tasks.size) return null
321
322
if (nextIndex.compareAndSet(index, index + 1)) {
323
return index to tasks[index]
324
}
325
}
326
}
327
328
fun completeTask(index: Int, result: String) {
329
results[index].value = result
330
processed[index].value = true
331
}
332
333
fun isComplete(): Boolean {
334
for (i in 0 until processed.size) {
335
if (!processed[i].value) return false
336
}
337
return true
338
}
339
340
fun getResults(): List<String?> {
341
return (0 until results.size).map { results[it].value }
342
}
343
}
344
```
345
346
## Implementation Notes
347
348
### Performance Characteristics
349
350
- Each element in atomic arrays is a separate atomic variable
351
- Index access is O(1) but involves atomic operations
352
- Memory overhead: each element requires atomic field updater setup
353
- Best suited for scenarios with known, fixed-size collections
354
355
### Thread Safety
356
357
- All operations on individual array elements are atomic
358
- Array size is immutable once created
359
- Concurrent access to different indices is fully thread-safe
360
- Operations on the same index are serialized through atomic operations