That's actually an entirely reasonable question, Rust's memory model is scarcely as well nailed down as the Java Memory Model (which is a GC model that does promise memory safety under concurrency and is worth reading about if you'd like to see how much thought is needed).
However in a sense Rust is cheating. Java has to do a lot of work because they can't stop you writing a data race in Java, so they want that to be safe anyway if it happens. (Safe) Rust just won't emit the data race in the first place.
A data race requires (as mentioned below in the thread about Python concurrency) that there's mutation concurrently with access to the same memory. In Java that's a bad idea, but it does happen, usually by mistake. In (Safe) Rust mutation requires that nobody else has a shared (immutable) reference to the object, so the data race can't occur because if we can mutate something by definition nobody else has a reference to it - programs with this mistake won't compile.
[0] https://www.merriam-webster.com/words-at-play/sealioning-int....
Edit: Just realized you said "even with garbage collection", so you weren't talking about Rust. Never mind.