0
# Lock-Free Synchronization
1
2
Reentrant locks and lock-free synchronization primitives for thread-safe coordination without blocking. This API provides alternatives to traditional blocking synchronization mechanisms.
3
4
## Capabilities
5
6
### Lock Factory Function
7
8
Creates reentrant lock instances for thread-safe coordination.
9
10
```kotlin { .api }
11
/**
12
* Creates a reentrant lock for thread-safe coordination
13
* @returns ReentrantLock instance for lock-based synchronization
14
*/
15
fun reentrantLock(): ReentrantLock
16
```
17
18
**Usage Examples:**
19
20
```kotlin
21
import kotlinx.atomicfu.locks.*
22
23
// Create a reentrant lock
24
val lock = reentrantLock()
25
```
26
27
### ReentrantLock Operations
28
29
Thread-safe lock implementation with support for reentrant locking.
30
31
```kotlin { .api }
32
/**
33
* Reentrant lock for thread-safe coordination
34
*/
35
class ReentrantLock {
36
/** Acquires the lock, blocking if necessary */
37
fun lock(): Unit
38
39
/** Releases the lock */
40
fun unlock(): Unit
41
42
/** Attempts to acquire the lock without blocking */
43
fun tryLock(): Boolean
44
45
/** Executes action while holding the lock */
46
inline fun <T> withLock(action: () -> T): T
47
}
48
```
49
50
**Usage Examples:**
51
52
```kotlin
53
import kotlinx.atomicfu.locks.*
54
55
class ThreadSafeCounter {
56
private val lock = reentrantLock()
57
private var count = 0
58
59
fun increment(): Int {
60
return lock.withLock {
61
++count
62
}
63
}
64
65
fun get(): Int {
66
return lock.withLock {
67
count
68
}
69
}
70
71
fun tryIncrement(): Boolean {
72
return if (lock.tryLock()) {
73
try {
74
count++
75
true
76
} finally {
77
lock.unlock()
78
}
79
} else {
80
false
81
}
82
}
83
}
84
85
// Manual lock/unlock pattern
86
class ManualLockExample {
87
private val lock = reentrantLock()
88
private val items = mutableListOf<String>()
89
90
fun addItem(item: String) {
91
lock.lock()
92
try {
93
items.add(item)
94
} finally {
95
lock.unlock()
96
}
97
}
98
}
99
```
100
101
### Lock-Based Data Structures
102
103
Common patterns for building thread-safe data structures using locks.
104
105
**Usage Examples:**
106
107
```kotlin
108
// Pattern 1: Thread-safe cache
109
class ThreadSafeCache<K, V> {
110
private val lock = reentrantLock()
111
private val cache = mutableMapOf<K, V>()
112
113
fun get(key: K): V? {
114
return lock.withLock {
115
cache[key]
116
}
117
}
118
119
fun put(key: K, value: V): V? {
120
return lock.withLock {
121
cache.put(key, value)
122
}
123
}
124
125
fun computeIfAbsent(key: K, factory: (K) -> V): V {
126
return lock.withLock {
127
cache.computeIfAbsent(key, factory)
128
}
129
}
130
}
131
132
// Pattern 2: Producer-consumer queue
133
class ThreadSafeQueue<T> {
134
private val lock = reentrantLock()
135
private val queue = ArrayDeque<T>()
136
137
fun offer(item: T) {
138
lock.withLock {
139
queue.offer(item)
140
}
141
}
142
143
fun poll(): T? {
144
return lock.withLock {
145
queue.poll()
146
}
147
}
148
149
fun size(): Int {
150
return lock.withLock {
151
queue.size
152
}
153
}
154
}
155
156
// Pattern 3: Lazy initialization
157
class ThreadSafeLazy<T>(private val initializer: () -> T) {
158
private val lock = reentrantLock()
159
private var value: T? = null
160
private var initialized = false
161
162
fun get(): T {
163
if (initialized) {
164
@Suppress("UNCHECKED_CAST")
165
return value as T
166
}
167
168
return lock.withLock {
169
if (!initialized) {
170
value = initializer()
171
initialized = true
172
}
173
@Suppress("UNCHECKED_CAST")
174
value as T
175
}
176
}
177
}
178
179
// Pattern 4: Multiple readers, single writer
180
class ReadWriteExample {
181
private val lock = reentrantLock()
182
private var data = ""
183
184
fun read(): String {
185
return lock.withLock {
186
data
187
}
188
}
189
190
fun write(newData: String) {
191
lock.withLock {
192
data = newData
193
}
194
}
195
196
fun update(transform: (String) -> String) {
197
lock.withLock {
198
data = transform(data)
199
}
200
}
201
}
202
```
203
204
### Best Practices
205
206
When using locks in atomicfu:
207
208
1. **Use `withLock` for exception safety**: Always prefer `withLock {}` over manual `lock()`/`unlock()` pairs
209
2. **Keep critical sections small**: Minimize the amount of work done while holding a lock
210
3. **Avoid nested locks**: Be careful of deadlock potential when using multiple locks
211
4. **Consider atomic operations first**: Use atomic operations when possible instead of locks for better performance
212
5. **Handle `tryLock()` properly**: Always check the return value and handle both success and failure cases
213
214
**Example of proper exception handling:**
215
216
```kotlin
217
class SafeLockUsage {
218
private val lock = reentrantLock()
219
private val resources = mutableListOf<String>()
220
221
// Preferred: withLock handles exceptions automatically
222
fun safeAdd(item: String) {
223
lock.withLock {
224
resources.add(item)
225
// Exception here is handled properly
226
}
227
}
228
229
// Manual lock/unlock with proper exception handling
230
fun manualAdd(item: String) {
231
lock.lock()
232
try {
233
resources.add(item)
234
} finally {
235
lock.unlock() // Always called, even if exception occurs
236
}
237
}
238
239
// tryLock pattern
240
fun conditionalAdd(item: String): Boolean {
241
return if (lock.tryLock()) {
242
try {
243
resources.add(item)
244
true
245
} finally {
246
lock.unlock()
247
}
248
} else {
249
false // Could not acquire lock
250
}
251
}
252
}
253
```