Rust's concurrency story begins with `std::thread::spawn`, which takes a closure and returns a `JoinHandle`. Calling `.join().unwrap()` on the handle blocks the current thread until the spawned thread has finished. Closures sent to threads almost always need the `move` keyword so that they own the data they operate on rather than borrowing it from the spawning thread, which would otherwise cause lifetime problems once the spawning thread moves on.
Two marker traits underpin safe concurrency. `Send` indicates that a value of a type can be transferred to another thread, while `Sync` indicates that a value can be referenced from multiple threads — formally, `&T` is `Send` whenever `T` is `Sync`. Most standard types implement both automatically. The single-threaded reference-counted pointer `Rc
For shared state across threads, the standard library offers `Arc
When shared state is awkward, channels provide an alternative based on message passing. The `std::sync::mpsc` module — short for multiple producer, single consumer — gives you a sender `tx` and a receiver `rx`. The sender hands values to the receiver, which can collect them. Channels naturally serialize access through communication rather than through shared locks, and they are often the most ergonomic way to coordinate work between threads.