Rust 并发实战:用 Arc 与 Mutex 做线程安全的计数

test12026-09-224 次阅读

共享状态是并发的头号难题

Rust 的所有权系统把「数据竞争」挡在了编译期。当多个线程要修改同一份数据时,不能简单地共享一个可变变量,必须用 Arc 做原子引用计数、用 Mutex 做互斥锁,把可变访问串行化。下面用一个并发计数器说明完整写法。

use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::thread;

fn main() {
    let counter = Arc::new(Mutex::new(0u64));
    let (tx, rx) = mpsc::channel::<u64>();

    let mut handles = Vec::new();
    for _ in 0..4 {
        let counter = Arc::clone(&counter);
        let tx = tx.clone();
        handles.push(thread::spawn(move || {
            for _ in 0..1000 {
                let mut v = counter.lock().unwrap();
                *v += 1;
            }
            tx.send(1).unwrap();
        }));
    }
    drop(tx);

    for h in handles {
        h.join().unwrap();
    }
    for _ in rx {}

    println!("final count = {}", *counter.lock().unwrap());
}

关键的三处设计

  • Arc 让四个线程共享同一份 counter,clone 只是增加引用计数,开销极低。
  • Mutex 保证同一时刻只有一个线程能 lock 并改写数值,把竞争变成串行。
  • mpsc 通道用来等所有工作线程完成任务,主线程 join 之后才能安全读取结果。

锁竞争与替代方案

上面的例子最终会稳定打印 4000。但 Mutex 在高频写入时是性能瓶颈,每个线程都要抢同一把锁。如果只是一个计数器,改用 std::sync::atomic 的 AtomicU64 能去掉锁、性能更好;如果是多生产者多消费者队列,crossbeam-channel 比标准库 mpsc 更适合。

什么时候该上并发

  • CPU 密集型任务(解析、计算)用能并行的工作线程能直接缩短耗时。
  • IO 密集型任务优先用异步(Tokio),线程更适合需要真正并行计算的场景。
  • 共享状态越少越好,能用通道传递所有权就别用锁,锁只留给必须共享的少量数据。
T

test1

文章作者

共享状态是并发的头号难题 Rust 的所有权系统把「数据竞争」挡在了编译期。当多个线程要修改同一份数据时,不能简单地共...

分类
技术
发布时间
2026-09-22
字数
约 1219 字
阅读
4 次