Adding an object to a collection is not a simple operation. It's a sequence of events.
Events can be simultaneous, but when we're talking about sequences of events, either the sequences overlap, or they are disjoint.
Computer hardware is designed such that, if two events happen simultaneously, the outcome will always be as if one of them happened before the other. The reason is simple. Suppose thread A assigns v=3
, and suppose thread B assigns v=5
. If thread A goes first, the final outcome will be v==5
. If thread B goes first, the final outcome will be v==3
. No programmer ever wants to have to deal with a third possible outcome. What would it even be?
Regardless of what happens in the hardware, when we talk about events in programs, we never say "simultaneous." We trust the hardware to behave as if that possibility did not exist.
When we talk about overlapping sequences of operations (e.g., adding objects to some collection), that's a major concern. That's what concurrency control is all about.
If concurrency control is done right, then after two threads each insert an object into a collection, the collection will be guaranteed to contain both objects. If it's done wrong, almost anything is possible, (including the possibility that any further attempt to use the collection will crash the program.)
You could literally spend years studying all of the different methods of concurrency control.