Skip to content

线程基础面试题

1. 线程的基本概念

问题:什么是线程?线程和进程有什么区别?

答案

  • 线程:操作系统能够进行运算调度的最小单位。
  • 区别
    • 进程是资源分配的基本单位,线程是CPU调度的基本单位。
    • 进程拥有独立的内存空间,线程共享进程的内存空间。
    • 进程间通信需要IPC,线程间通信可以直接访问共享变量。
    • 进程创建和销毁的开销大,线程创建和销毁的开销小。

2. Java中创建线程的方式

问题:Java中有哪些创建线程的方式?

答案

  • 继承Thread类
java
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread is running");
    }
}

MyThread thread = new MyThread();
thread.start();
  • 实现Runnable接口
java
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable is running");
    }
}

Thread thread = new Thread(new MyRunnable());
thread.start();
  • 实现Callable接口
java
public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "Callable is running";
    }
}

ExecutorService executor = Executors.newFixedThreadPool(1);
Future<String> future = executor.submit(new MyCallable());
String result = future.get();
  • 使用线程池
java
ExecutorService executor = Executors.newFixedThreadPool(10);
executor.submit(() -> {
    System.out.println("Thread is running");
});

3. 线程的生命周期

问题:线程的生命周期有哪些状态?

答案

  • NEW:新建状态,线程对象已创建但未启动。
  • RUNNABLE:可运行状态,线程正在运行或等待CPU。
  • BLOCKED:阻塞状态,线程等待锁。
  • WAITING:等待状态,线程等待其他线程通知。
  • TIMED_WAITING:超时等待状态,线程等待指定时间。
  • TERMINATED:终止状态,线程已执行完毕。

4. 线程的优先级

问题:线程的优先级有什么作用?

答案

  • 优先级:表示线程的重要程度,优先级高的线程更容易获得CPU时间。
  • 范围:1-10,默认为5。
  • 常量
    • Thread.MIN_PRIORITY = 1
    • Thread.NORM_PRIORITY = 5
    • Thread.MAX_PRIORITY = 10

示例

java
Thread thread = new Thread();
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();

5. 线程的守护线程

问题:什么是守护线程?

答案

  • 守护线程:为其他线程服务的线程,当所有非守护线程结束时,守护线程也会结束。
  • 特点
    • 不会阻止JVM退出。
    • 通常用于后台任务,如垃圾回收。

示例

java
Thread thread = new Thread(() -> {
    while (true) {
        System.out.println("Daemon thread is running");
    }
});
thread.setDaemon(true);
thread.start();

6. 线程的sleep和wait

问题:sleep和wait有什么区别?

答案

  • sleep
    • Thread类的方法。
    • 释放CPU,不释放锁。
    • 可以指定睡眠时间。
    • 不需要同步块。
  • wait
    • Object类的方法。
    • 释放CPU和锁。
    • 需要其他线程notify或notifyAll唤醒。
    • 需要在同步块中使用。

示例

java
// sleep
Thread.sleep(1000);

// wait
synchronized (object) {
    object.wait();
}

7. 线程的join

问题:join方法的作用是什么?

答案

  • join:等待线程执行完毕。
  • 作用
    • 等待线程结束。
    • 可以指定等待时间。

示例

java
Thread thread = new Thread(() -> {
    System.out.println("Thread is running");
});
thread.start();
thread.join();
System.out.println("Thread is finished");

8. 线程的yield

问题:yield方法的作用是什么?

答案

  • yield:让出CPU,让其他线程有机会执行。
  • 作用
    • 提示调度器当前线程愿意让出CPU。
    • 不保证一定会让出CPU。

示例

java
Thread.yield();

9. 线程的interrupt

问题:如何中断线程?

答案

java
Thread thread = new Thread(() -> {
    while (!Thread.currentThread().isInterrupted()) {
        System.out.println("Thread is running");
    }
});
thread.start();
thread.interrupt();

10. 线程的同步

问题:如何实现线程同步?

答案

  • synchronized关键字
java
public synchronized void method() {
}

synchronized (object) {
}
  • ReentrantLock
java
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
} finally {
    lock.unlock();
}

11. 线程的通信

问题:如何实现线程间通信?

答案

  • wait/notify
java
synchronized (object) {
    object.wait();
}

synchronized (object) {
    object.notify();
}
  • Condition
java
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();

condition.await();
condition.signal();

12. 线程的死锁

问题:什么是死锁?如何避免?

答案

  • 死锁:两个或多个线程互相等待对方释放锁,导致程序无法继续执行。
  • 避免方法
    • 避免嵌套锁。
    • 按照固定顺序获取锁。
    • 设置锁的超时时间。
    • 使用死锁检测。

13. 线程的活锁

问题:什么是活锁?如何避免?

答案

  • 活锁:线程不断改变状态,但无法继续执行。
  • 避免方法
    • 增加随机等待时间。
    • 设置重试次数限制。

14. 线程的饥饿

问题:什么是线程饥饿?如何避免?

答案

  • 线程饥饿:低优先级线程无法获得CPU时间。
  • 避免方法
    • 使用公平锁。
    • 设置合理的线程优先级。
    • 使用线程池。

15. 线程的上下文切换

问题:什么是线程的上下文切换?

答案

  • 上下文切换:CPU从一个线程切换到另一个线程的过程。
  • 开销
    • 保存当前线程的状态。
    • 恢复目标线程的状态。
    • 刷新缓存。

16. 线程的可见性

问题:什么是线程的可见性?如何保证?

答案

  • 可见性:一个线程对共享变量的修改,对其他线程可见。
  • 保证方法
    • 使用volatile关键字。
    • 使用synchronized关键字。
    • 使用final关键字。

示例

java
private volatile boolean flag = false;

17. 线程的原子性

问题:什么是线程的原子性?如何保证?

答案

  • 原子性:操作不可分割,要么全部成功,要么全部失败。
  • 保证方法
    • 使用synchronized关键字。
    • 使用ReentrantLock。
    • 使用Atomic类。

示例

java
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();

18. 线程的有序性

问题:什么是线程的有序性?如何保证?

答案

  • 有序性:程序的执行顺序按照代码的顺序执行。
  • 保证方法
    • 使用volatile关键字。
    • 使用synchronized关键字。
    • 使用final关键字。

19. volatile关键字

问题:volatile关键字的作用是什么?

答案

  • 作用
    • 保证可见性。
    • 禁止指令重排序。
    • 不保证原子性。

示例

java
private volatile boolean flag = false;

20. ThreadLocal

问题:ThreadLocal的作用是什么?

答案

  • ThreadLocal:线程本地变量,每个线程拥有独立的副本。
  • 作用
    • 线程隔离。
    • 避免参数传递。
    • 保存线程上下文。

示例

java
ThreadLocal<String> threadLocal = new ThreadLocal<>();
threadLocal.set("value");
String value = threadLocal.get();
threadLocal.remove();

21. InheritableThreadLocal

问题:InheritableThreadLocal的作用是什么?

答案

  • InheritableThreadLocal:继承ThreadLocal,子线程可以继承父线程的ThreadLocal值。

示例

java
InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();
inheritableThreadLocal.set("value");
new Thread(() -> {
    String value = inheritableThreadLocal.get();
}).start();

22. 线程的异常处理

问题:如何处理线程的异常?

答案

java
Thread thread = new Thread(() -> {
    throw new RuntimeException("Exception");
});
thread.setUncaughtExceptionHandler((t, e) -> {
    System.out.println("Exception in thread " + t.getName() + ": " + e.getMessage());
});
thread.start();

23. 线程的堆栈跟踪

问题:如何获取线程的堆栈跟踪?

答案

java
Thread thread = Thread.currentThread();
StackTraceElement[] stackTrace = thread.getStackTrace();
for (StackTraceElement element : stackTrace) {
    System.out.println(element);
}

24. 线程的组

问题:什么是线程组?

答案

  • 线程组:用于统一管理一组线程。
  • 作用
    • 统一设置优先级。
    • 统一设置守护线程。
    • 统一处理异常。

示例

java
ThreadGroup group = new ThreadGroup("myGroup");
Thread thread = new Thread(group, () -> {
    System.out.println("Thread is running");
});

25. 线程的最佳实践

问题:使用线程的最佳实践有哪些?

答案

  • 使用线程池而不是直接创建线程。
  • 使用Runnable而不是继承Thread。
  • 使用volatile保证可见性。
  • 使用synchronized或ReentrantLock保证线程安全。
  • 使用ThreadLocal实现线程隔离。
  • 使用InheritableThreadLocal实现线程继承。
  • 使用join等待线程结束。
  • 使用interrupt中断线程。
  • 使用setUncaughtExceptionHandler处理异常。
  • 避免死锁、活锁、饥饿。