Java线程基础面试复习笔记
1. 线程与进程的区别
进程是正在运行程序的实例,线程是进程中的执行单元。主要区别:
- 内存空间:不同进程使用不同的内存空间,同一进程下的线程共享内存空间
- 资源开销:线程更轻量,线程上下文切换成本比进程上下文切换低
- 通信方式:线程间通信更简单(共享内存),进程间通信需要特殊机制(IPC)
2. 并发与并行
- 并发(Concurrency):同一时间应对多件事情的能力,多个线程轮流使用CPU资源
- 并行(Parallelism):同一时间动手做多件事情的能力,多核CPU同时执行多个线程
补充:并发是逻辑上的同时发生,并行是物理上的同时发生
3. 创建线程的方式
四种主要方式:
- 继承Thread类 - 重写run()方法
- 实现Runnable接口 - 实现run()方法(推荐,避免单继承限制)
- 实现Callable接口 - 实现call()方法,有返回值
- 线程池创建 - 项目中推荐使用方式
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()方法保证顺序执行:
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. 停止线程的方法
三种方式:
- 使用标志位:设置boolean变量控制run()方法退出(推荐)
- interrupt()方法:
- 打断阻塞线程(sleep/wait/join)会抛出InterruptedException
- 打断正常线程,通过检查中断状态决定是否退出
- stop()方法:已废弃,不推荐使用
最佳实践:
// 标志位方式
private volatile boolean running = true;
public void run() {while (running) {// 执行任务}
}// interrupt方式
public void run() {while (!Thread.currentThread().isInterrupted()) {// 执行任务}
}