Appearance
线程基础面试题
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处理异常。
- 避免死锁、活锁、饥饿。
