Spawning Threads
Run code concurrently.
Spawning Threads is a free Learn Rust Coding lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Learn Rust Coding learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is a Thread?
A thread lets your program run code concurrently. The operating system can schedule multiple threads, so work can overlap.
Rust's standard library exposes threads through the std::thread module. These are native OS threads, sometimes called 1:1 threads.
In this lesson you will learn to start new threads and control how they run.
Spawning with thread::spawn
You create a new thread by calling thread::spawn and passing it a closure. The closure holds the code the new thread will run.
The call returns immediately with a JoinHandle, while the spawned thread runs in the background.
use std::thread;
fn main() {
thread::spawn(|| {
println!("hello from a thread");
});
println!("hello from main");
}Main May Finish First
When main returns, the whole process ends, even if spawned threads are still running.
So the program above might print only the main message. The background thread may not get a chance to run before the process exits.
We need a way to wait for threads to finish.
Waiting with join
The JoinHandle returned by spawn has a join method. Calling it blocks the current thread until the spawned thread finishes.
This guarantees the spawned thread runs to completion before main continues.
use std::thread;
fn main() {
let handle = thread::spawn(|| {
println!("worker done");
});
handle.join().unwrap();
println!("main done");
}Interleaving Output
When two threads run at once, their output can interleave in unpredictable ways. The OS decides the schedule.
Running the same program twice may produce different orderings. Never rely on a specific order without synchronization.
use std::thread;
fn main() {
let handle = thread::spawn(|| {
for i in 1..4 {
println!("thread: {}", i);
}
});
for i in 1..4 {
println!("main: {}", i);
}
handle.join().unwrap();
}Pausing with sleep
You can pause a thread with thread::sleep, which takes a Duration. This yields the CPU so other threads can make progress.
Sleeping is useful in examples to make interleaving more visible, but avoid it for real synchronization.
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(|| {
for i in 1..4 {
println!("spawned: {}", i);
thread::sleep(Duration::from_millis(1));
}
});
thread::sleep(Duration::from_millis(10));
}Spawning Many Threads
You can spawn several threads in a loop and collect their handles into a vector.
Later you iterate the vector and join each handle, ensuring every thread completes before the program ends.
use std::thread;
fn main() {
let mut handles = vec![];
for id in 0..3 {
let h = thread::spawn(move || {
println!("thread {}", id);
});
handles.push(h);
}
for h in handles {
h.join().unwrap();
}
}Naming Threads with Builder
The thread::Builder type lets you configure a thread before spawning. You can set a name and a stack size.
Named threads make panic messages and debugging easier to read.
use std::thread;
fn main() {
let h = thread::Builder::new()
.name("worker".into())
.spawn(|| {
println!("running in named thread");
})
.unwrap();
h.join().unwrap();
}Panics Stay in the Thread
If a spawned thread panics, it does not crash the whole program by default. The panic is contained in that thread.
When you call join on a panicked thread, you get an Err. This lets the parent detect the failure.
use std::thread;
fn main() {
let h = thread::spawn(|| {
panic!("boom");
});
let result = h.join();
println!("joined, is_err = {}", result.is_err());
}Current Thread Info
You can inspect the running thread with thread::current. It returns a handle whose name method gives the optional thread name.
The main thread is also a real thread, usually named main.
use std::thread;
fn main() {
let current = thread::current();
println!("name: {:?}", current.name());
}Returning Values from Threads
The closure passed to spawn can return a value. That value comes back wrapped in Ok when you call join.
This is a simple way to compute something on another thread and read the result later.
use std::thread;
fn main() {
let h = thread::spawn(|| {
let sum: i32 = (1..=10).sum();
sum
});
let total = h.join().unwrap();
println!("total = {}", total);
}Quick Check
Test your understanding of spawning threads.
Recap
You learned to start threads with thread::spawn and a closure, which returns a JoinHandle.
Calling join waits for completion and surfaces the return value or a panic. Output between threads can interleave unpredictably, and the Builder lets you name threads.
Next you will see how to move data into the threads you spawn.
Frequently asked questions
Is the “Spawning Threads” lesson free?
Yes — the full text of “Spawning Threads” is free to read here on the web, and the Learn Rust Coding course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Learn Rust Coding course, upgrade to CoddyKit PRO.
What will I learn in “Spawning Threads”?
Run code concurrently. You practise Learn Rust Coding with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Learn Rust Coding?
No prior experience is required. Learn Rust Coding on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Spawning Threads” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Learn Rust Coding lesson?
Yes. Every Learn Rust Coding lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.