Java线程基础面试复习笔记

1. 线程与进程的区别

进程 是正在运行程序的实例,线程是进程中的执行单元。主要区别:

  • 内存空间:不同进程使用不同的内存空间,同一进程下的线程共享内存空间
  • 资源开销:线程更轻量,线程上下文切换成本比进程上下文切换低
  • 通信方式:线程间通信更简单(共享内存),进程间通信需要特殊机制(IPC)

2. 并发与并行

  • 并发(Concurrency):同一时间应对多件事情的能力,多个线程轮流使用CPU资源
  • 并行(Parallelism):同一时间动手做多件事情的能力,多核CPU同时执行多个线程

补充:并发是逻辑上的同时发生,并行是物理上的同时发生

3. 创建线程的方式

四种主要方式:

  1. 继承Thread类 - 重写run()方法
  2. 实现Runnable接口 - 实现run()方法(推荐,避免单继承限制)
  3. 实现Callable接口 - 实现call()方法,有返回值
  4. 线程池创建 - 项目中推荐使用方式

Runnable vs Callable:

  • Runnable的run()方法无返回值,Callable的call()方法有返回值
  • Callable可以抛出异常,Runnable的异常只能内部处理
  • Callable需要配合FutureTask获取结果

4. run()与start()的区别

  • start():启动线程,由JVM调用run()方法,只能调用一次
  • run():封装线程执行的代码,可以被调用多次,直接调用run()不会创建新线程

5. 线程状态及转换

六种状态:

  • NEW(新建):线程对象创建,未调用start()
  • RUNNABLE(可运行):调用start()后,包括就绪和运行状态
  • BLOCKED(阻塞):等待获取synchronized锁
  • WAITING(等待):调用wait()、join()等方法,无限期等待
  • TIMED_WAITING(超时等待):调用sleep()、wait(timeout)等方法
  • TERMINATED(终止):线程执行完毕或异常终止

状态转换关键点:

  • 获取锁失败 → BLOCKED状态
  • wait()方法 → WAITING状态,notify()/notifyAll()唤醒
  • sleep()方法 → TIMED_WAITING状态,时间到自动唤醒

6. 线程执行顺序控制

使用join()方法保证顺序执行:

java 复制代码
T1.start();
T1.join(); // 等待T1执行完
T2.start();
T2.join(); // 等待T2执行完
T3.start();

补充:还可以使用CountDownLatch、CyclicBarrier等同步工具

7. notify()与notifyAll()

  • notify():随机唤醒一个等待的线程
  • notifyAll():唤醒所有等待的线程

面试技巧:通常推荐使用notifyAll()避免死锁风险

8. wait()与sleep()的区别

相同点:

都会让当前线程暂时放弃CPU使用权,进入阻塞状态

关键区别:

  • 归属不同:sleep()是Thread的静态方法,wait()是Object的实例方法
  • 锁的处理:wait()会释放对象锁,sleep()不会释放锁
  • 唤醒方式:wait()可被notify()唤醒,sleep()只能等时间到或被interrupt()
  • 使用条件:wait()必须在synchronized块中使用,sleep()无此限制

9. 停止线程的方法

三种方式:

  1. 使用标志位:设置boolean变量控制run()方法退出(推荐)
  2. interrupt()方法
    • 打断阻塞线程(sleep/wait/join)会抛出InterruptedException
    • 打断正常线程,通过检查中断状态决定是否退出
  3. stop()方法:已废弃,不推荐使用

最佳实践:

java 复制代码
// 标志位方式
private volatile boolean running = true;
public void run() {
    while (running) {
        // 执行任务
    }
}

// interrupt方式
public void run() {
    while (!Thread.currentThread().isInterrupted()) {
        // 执行任务
    }
}