juc面试题
时间: 2025-05-11 19:28:15 浏览: 35
### Java JUC 并发包常见面试题及答案
#### 1. **什么是线程池?为什么使用线程池?**
线程池是一种管理多个线程的方式,它通过预先创建一定数量的线程来处理任务请求。这样可以减少频繁创建和销毁线程带来的性能开销,并提高系统的响应速度。
`ThreadPoolExecutor` 是 `java.util.concurrent` 包中实现线程池的核心类之一。它的设计目标是在执行 `execute()` 方法时尽可能避免获取全局锁,从而提升可扩展性和效率[^2]。
---
#### 2. **Java 中如何创建线程?有哪些方式?**
在 Java 中可以通过以下几种方式创建线程:
- 继承 `Thread` 类并重写其 `run()` 方法;
- 实现 `Runnable` 接口并通过传递给 `Thread` 构造函数实例化线程;
- 实现 `Callable` 接口(支持返回值和异常抛出),并通过 `FutureTask` 将其实例封装后提交到线程池中运行。
每种方式都有各自的适用场景,其中推荐优先使用接口形式(如 `Runnable` 或 `Callable`),因为这种方式更灵活且不会占用继承的机会。
---
#### 3. **sleep() 和 wait() 的区别是什么?**
两者的主要区别如下:
- `sleep()` 方法会让当前线程暂停一段时间,但它不会释放对象锁;适用于简单的定时延迟需求。
- `wait()` 方法则会使得当前线程进入等待状态直到其他线程调用 `notify()` 或 `notifyAll()` 唤醒该线程,同时还会释放对象锁;主要用于线程间协作[^3]。
需要注意的是,`wait()` 必须在一个同步块内部被调用,而 `sleep()` 则可以直接使用于任何地方。
---
#### 4. **什么是上下文切换?为什么会发生上下文切换?**
当操作系统需要从一个正在运行的任务切换到另一个待调度的任务时就会触发所谓的“上下文切换”。这种现象可能由于 CPU 时间片耗尽、I/O 请求阻塞等原因引起。
对于多线程环境而言,过多的上下文切换可能会带来额外的性能损耗,因此合理控制并发度以及优化资源分配策略显得尤为重要[^4]。
---
#### 5. **ThreadLocal 的作用及其原理是什么?**
`ThreadLocal` 提供了一种机制允许每个线程拥有独立副本的数据存储区域——即所谓“局部变量”,这些数据之间相互隔离互不影响。具体来说,它是基于每个 `Thread` 对象内部维护的一个名为 `ThreadLocalMap` 的哈希表结构来实现这一功能的。
以下是关于 `ThreadLocal` 使用的一段代码示例:
```java
public class ThreadLocalExample {
private static final ThreadLocal<Integer> threadLocalValue = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
int value = (int)(Math.random()*10);
System.out.println(Thread.currentThread().getName()+" sets "+value);
threadLocalValue.set(value);
try { Thread.sleep(10); } catch(Exception e){}
System.out.println(Thread.currentThread().getName()+": retrieves "+threadLocalValue.get());
};
Thread t1=new Thread(task,"T1");
Thread t2=new Thread(task,"T2");
t1.start();t2.start();
}
}
```
---
#### 6. **CountDownLatch 和 CyclicBarrier 的主要区别在哪里?**
虽然它们都属于同步辅助工具类别下用来协调多个线程之间的操作关系的对象,但是二者存在显著差异:
- `CountDownLatch`: 只能一次性减计数至零之后才能打开门闩放行后续动作, 而一旦到达终点就不能重新设置初始值.
- `CyclicBarrier`: 支持循环利用屏障点的功能特性, 即每次达到设定次数后都可以自动恢复原状继续工作.
---
###
阅读全文
相关推荐

















