Both C# and Java define that
* volatile reads have acquire semantics
* volatile writes have release semantics
My
The power of the acquire/release semantics isn't so much about how soon other threads see the newly written value of the volatile field itself, but rather in the way volatile operations establish a happens-before relation across different threads. If a thread A reads a volatile field and sees a value that was written to that field in another thread B then thread A is also guaranteed to see values written to other (not necessarily volatile) variables by thread B before the point where it did the volatile write. This looks like cache flushing but only from the point of view of a thread that read the volatile, other threads that don't touch the volatile field have no ordering guarantees with respect to B and might see some of its earlier non-volatile writes but not others if the compiler/JIT is so inclined.
Monitor acquires/releases are similarly characterised by their induced happens-before relation - actions by one thread before a release of a monitor are guaranteed to be visible after a subsequent acquire of the same monitor by another thread. Volatiles give you the same ordering guarantees as monitor synchronisation but without blocking.