第 14 章 · 多线程

14.1 线程概述

线程是程序执行的最小单元,一个进程可包含多个线程,线程共享进程的内存,但各自独立调度。多线程提升并发与响应性。

14.2 线程的创建

方式一:继承 Thread 类

class MyThread extends Thread {
    public void run() { System.out.println("线程运行"); }
}
new MyThread().start();   // start 启动新线程,调用 run 只是普通方法

方式二:实现 Runnable 接口(推荐)

class Task implements Runnable {
    public void run() { System.out.println("任务运行"); }
}
new Thread(new Task()).start();
  • 推荐 Runnable:Java 单继承,实现接口不占继承名额,且任务与线程解耦。
  • 调用 start() 才真正创建线程;直接调 run() 是普通调用,不并发。
  • 后台线程(daemon)setDaemon(true),主线程结束即退出。

14.3 线程生命周期

新建(New)→ 就绪(Runnable)→ 运行(Running)→ 阻塞(Blocked/Waiting/Timed Waiting)→ 终止(Terminated)。start 进入就绪,抢到 CPU 才运行;sleep/join/wait 进入等待,synchronized 竞争失败进入阻塞。

14.4 线程调度

  • 优先级setPriority(1~10),仅作为调度参考,不保证顺序。
  • 休眠Thread.sleep(ms) 让出 CPU。
  • 让步Thread.yield() 建议让出,不保证。
  • 插队join() 等待目标线程结束后再继续。

14.5 多线程同步

多个线程共享数据时会出现线程安全问题(竞态),需同步保证原子性。

class Counter {
    private int count = 0;
    public synchronized void increment() { count++; }  // 同步方法
    public synchronized int get() { return count; }
}
  • 同步代码块synchronized(obj) { ... } 锁定对象,保证互斥。
  • 同步方法:锁的是 this;静态同步方法锁的是类对象(Class)。
  • 死锁:多个线程互相持有对方需要的锁而永久阻塞,需避免循环等待。

本质:synchronized 基于 JVM 的监视器(monitor)锁,进入/退出自动加解锁;底层对应 C 的 pthread mutex 概念,但 Java 内置、无需手动 init/destroy。

14.6 多线程通信

wait()/notify()/notifyAll()(在 synchronized 内使用)实现线程协作——生产者/消费者模型:

synchronized (lock) {
    while (queue.isEmpty()) lock.wait();  // 等待
    // 消费...
    lock.notifyAll();                       // 唤醒等待线程
}

14.7 与其他语言对比

维度JavaCC++Python
线程内置 Thread/Runnablepthread 库std::threadthreading
同步synchronizedmutex/condmutex/lock_guardLock
内存模型JMM 规范无统一C++11 起有
局限繁琐GIL

关键差异:C 需手动管理 pthread 的创建、锁、销毁;C++ 用 RAII 包装锁;Python 有全局解释器锁(GIL),多线程无法真正并行 CPU 密集任务;Java 线程与同步内置于语言和 JVM,抽象层次最高、最易用。