Designing systems where data is shared and mutated concurrently by multiple threads is hard.
Approaches to make concurrency easier include:
- STM -- With STM, data can still be shared and mutated by multiple threads, but concurrent mutations are detected thanks to the use of transactions.
- Uniqueness types -- With uniqueness types, at most one reference to an object exists. So, by definition, it is impossible to mutate the same data concurrently (you would need two references at least, one per thread).
- Immutability -- Avoid the problem of concurrent mutations altogether and share only immutable data.
- Actors -- Actors rely on asynchronous messages, and serialize the messages they receive, thus avoiding concurrent modifications.