Start here. This is the direct spoken answer to practice first.
Why this question matters
Concurrency bugs are often explained as stale reads when the real problem is a non-atomic state transition. Knowing the boundary of volatile prevents a visibility tool from being used as a lock replacement.
volatile tells the runtime that reads and writes of a field must observe specific visibility and ordering rules instead of being freely cached or reordered around that access. It does not turn several operations into one atomic operation. counter++ still reads the old value, adds one, and writes the result, so two threads can read the same value and lose an increment. I would use Interlocked.Increment for that counter or a lock when a larger invariant must be protected.