Monadic I/O (as I'm sure you know) just means that every I/O effect takes a world-state as an implicit parameter ("the world just before this action"), and returns a world-state ("the world just after this action") to thread into the next effect. In a concurrent program, I/O effects from multiple threads (and the outside world) may be interleaved or executed concurrently. Crudely, the world you changed a moment ago isn't necessarily the world you're about to change again. :)
Monadic I/O on its own doesn't make any guarantees, or impose any requirements, about locking external resources. If stdout is locked (from within the monad, or not), then that's the state the world arrives in for your effect. If not, then it's not. They are orthogonal concerns.