Not really related to coroutine but does anyone kn...
# coroutines
t
Not really related to coroutine but does anyone know what "larger actions" in this doc mean? and how does "reads and writes" differ from "increment"
e
same as Java (because it transforms to the same underlying bytecode): https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html
c
There are two big categories of operations: atomic and non-atomic. Atomic operations cannot be split into smaller operations (you can't half-read a variable). Incrementing a variable is not truly a single operation:
i++
is ‘look at what
i
is, add 1 to that, then update
i
to that’. In sequential programming, you don't have to care about that. In concurrent programming, it becomes very important, because different threads can see the states in-between operations. For example, let's imagine two threads (
a
and
b
) incrementing the counter variable: •
a
reads 0 •
b
reads 0 •
a
adds one -> 1 •
b
adds one -> 1 •
a
stores 1 in counter •
b
stores 1 in counter In the end, we did
++
two times, but the variable only stores 1, not 2, because the threads stepped on each other. If the order was different, it's possible to get 2 as well. This behavior is common to all languages that work across multiple cores, it's not related to Kotlin at all (https://en.m.wikipedia.org/wiki/Linearizability) Coroutines propose a solution for this: at all cost, avoid shared mutable state. • “shared between threads”: if you don't share objects, they can't be edited at the same time by two threads • “mutable state”: immutable objects can't be seen during their modification... They're not modified!
e
there's also memory ordering and observability - even atomic operations may not be observed in the same order across different threads. https://en.m.wikipedia.org/wiki/Memory_ordering
t
can you guy give an example code where volatile keyword make difference 🧐
e
Copy code
var flag = true
Thread {
    Thread.sleep(500)
    flag = false
}.start()
while (flag) {
    // do nothing
}
will loop infinitely, because there is nothing to cause a change in
flag
to be observed across different threads.
@Volatile
forces every access to be sequenced, so the loop will terminate.
🤩 1
but almost always, there are higher level synchronization tools that you should be using instead anyway - AtomicBoolean would also terminate here, for example
c
If you're using coroutines though, this is probably not the right approach. Coroutines try to avoid shared mutable state as much as possible, which, when done correctly, completely removes all these concerns
e
coroutines do use volatile and atomics internally :)
I agree though, you should build on top of what Kotlin provides instead of using low-level atomics as much as possible
t
@ephemient wow, how do you know such thing, that is amazing, are there any documentation about @Volatile that I can read more?
e
same as Java, follow the links above