Java 多线程中级面试题
1. 什么是线程死锁?如何避免?
死锁是指两个或多个线程在执行过程中,因争夺资源而造成的一种僵局。避免死锁的方法包括打破循环等待条件、使用顺序锁、使用超时机制等。
2. Java中`synchronized`和`ReentrantLock`有什么区别?
synchronized
是内置的同步机制,而ReentrantLock
是Java并发包中的显式锁。ReentrantLock
提供了更多的功能,如尝试非阻塞获取锁、可中断的锁获取等。
// synchronized
public synchronized void method() {
// 方法体
}
// ReentrantLock
Lock lock = new ReentrantLock();
lock.lock();
try {
// 方法体
} finally {
lock.unlock();
}
3. `volatile`关键字有什么作用?
volatile
关键字确保变量的读写操作对所有线程都是可见的,并且禁止指令重排。
volatile boolean running = true;
4. `ThreadLocal`变量是什么?它有什么作用?
ThreadLocal
变量是线程局部变量,每个线程都有自己独立的变量副本,用于隔离线程环境。
ThreadLocal<Integer> threadLocalValue = new ThreadLocal<>();
threadLocalValue.set(123);
5. `wait()`和`notify()`方法的作用是什么?
wait()
使当前线程等待,直到其他线程调用相同对象的notify()
或notifyAll()
方法。
synchronized (object) {
while (condition) {
object.wait();
}
// 线程被唤醒后执行的代码
}
6. `sleep()`和`wait()`有什么区别?
sleep()
是Thread
类的方法,它使当前线程暂停执行指定的时间,但不释放对象锁。wait()
是Object
类的方法,它使当前线程等待,直到被notify()
或notifyAll()
唤醒,并且释放对象锁。
7. `join()`方法的作用是什么?
join()
方法等待调用该方法的线程完成执行。
Thread thread = new Thread(() -> {
// 线程执行的操作
});
thread.start();
thread.join(); // 等待线程结束
8. `Callable`和`Runnable`有什么区别?
Callable
可以返回值和抛出异常,而Runnable
不能。
Callable<Integer> callable = () -> {
return 123;
};
Runnable runnable = () -> {
// 无返回值和异常抛出
};
9. `Future`和`FutureTask`有什么区别?
Future
是FutureTask
的接口,FutureTask
是Future
的实现类,用于处理异步计算的结果。
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
Integer result = futureTask.get(); // 获取计算结果
10. `ExecutorService`的作用是什么?
ExecutorService
是一个执行提交的 Runnable 任务的线程池。
ExecutorService executor = Executors.newFixedThreadPool(10);
executor.submit(callable);
executor.shutdown();
11. `ConcurrentHashMap`是如何保证线程安全的?
ConcurrentHashMap
通过分段锁机制来保证线程安全。
12. `CopyOnWriteArrayList`是如何工作的?
CopyOnWriteArrayList
在修改操作时复制整个底层数组,适用于读多写少的场景。
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("Element");
13. `ReadWriteLock`的作用是什么?
ReadWriteLock
允许多个读操作同时进行,但写操作是独占的。
ReadWriteLock lock = new ReentrantReadWriteLock();
Lock readLock = lock.readLock();
Lock writeLock = lock.writeLock();
readLock.lock();
try {
// 读操作
} finally {
readLock.unlock();
}
writeLock.lock();
try {
// 写操作
} finally {
writeLock.unlock();
}
14. `AtomicInteger`和`synchronized`有什么区别?
AtomicInteger
利用CAS操作实现无锁的原子操作,而synchronized
是锁机制。
AtomicInteger atomicInteger = new AtomicInteger(0);
atomicInteger.incrementAndGet();
15. `CountDownLatch`和`CyclicBarrier`有什么区别?
CountDownLatch
用于等待一组事件发生,而CyclicBarrier
用于等待线程达到一个共同点,然后继续执行。
CountDownLatch latch = new CountDownLatch(1);
latch.await(); // 等待计数器到达0
CyclicBarrier barrier = new CyclicBarrier(2);
barrier.await(); // 等待其他线程到达屏障
16. `Semaphore`的作用是什么?
Semaphore
用于控制对资源的访问,它是一个计数信号量。
Semaphore semaphore = new Semaphore(1);
semaphore.acquire(); // 请求一个许可
try {
// 访问资源
} finally {
semaphore.release(); // 释放许可
}
17. `Exchanger`的作用是什么?
Exchanger
用于在两个线程之间交换数据。
Exchanger<String> exchanger = new Exchanger<>();
Thread thread = new Thread(() -> {
String data = exchanger.exchange("Data");
});
thread.start();
String exchangedData = exchanger.exchange("Data to exchange");
18. `Fork/Join`框架的作用是什么?
Fork/Join
框架是一种用于并行计算的框架,它通过分而治之的方式将任务分解成更小的任务并行执行。
ForkJoinPool pool = new ForkJoinPool();
RecursiveTask<Integer> task = new RecursiveTask<Integer>() {
// 实现compute方法
};
pool.invoke(task);
19. `Phaser`和`Barrier`有什么区别?
Phaser
是Barrier
的扩展,它允许多个线程在多个阶段同步。
20. `CompletableFuture`的作用是什么?
CompletableFuture
用于编写异步代码,它提供了丰富的API来处理异步计算的结果。
CompletableFuture.supplyAsync(() -> {
return "Result";
}).thenAccept(result -> {
System.out.println(result);
});
21. `ThreadFactory`的作用是什么?
ThreadFactory
用于创建线程,它允许自定义线程的创建过程。
ThreadFactory factory = Executors.defaultThreadFactory();
Thread thread = factory.newThread(runnable);
22. `Executor`和`Executors`有什么区别?
Executor
是执行任务的接口,而Executors
是提供了一系列工厂方法来创建预定义配置的Executor
实现。
23. `BlockingQueue`的作用是什么?
BlockingQueue
是一个线程安全的队列,支持阻塞操作。
BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
queue.put(1); // 阻塞直到队列可用
Integer take = queue.take(); // 阻塞直到队列中有元素
24. `ArrayBlockingQueue`和`LinkedBlockingQueue`有什么区别?
ArrayBlockingQueue
是基于数组实现的有界队列,而LinkedBlockingQueue
是基于链表实现的可选边界队列。
25. `PriorityBlockingQueue`的作用是什么?
PriorityBlockingQueue
是一个线程安全的优先级队列。
PriorityBlockingQueue<Integer> queue = new PriorityBlockingQueue<>(11);
queue.put(5);
Integer take = queue.take(); // 按照优先级(自然顺序)取出元素
26. `DelayQueue`的作用是什么?
DelayQueue
是一个线程安全的无界队列,支持延迟操作。
DelayQueue<Delayed> queue = new DelayQueue<>();
queue.put(new Delayed(1, TimeUnit.SECONDS));
Delayed take = queue.take(); // 阻塞直到延迟到期
27. `SynchronousQueue`的作用是什么?
SynchronousQueue
是一个不存储元素的阻塞队列,每个插入操作必须等待一个移除操作。
SynchronousQueue<Runnable> queue = new SynchronousQueue<>();
queue.put(() -> {}); // 阻塞直到另一个线程移除元素
Runnable take = queue.take(); // 阻塞直到另一个线程插入元素
28. `ThreadFactoryBuilder`如何使用?
ThreadFactoryBuilder
用于构建自定义的ThreadFactory
。
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("my-thread-%d").build();
29. `Executors`类提供的线程池有什么特点?
Executors
类提供了固定大小、可缓存、单线程和定时/周期性任务的线程池实现。
30. `ScheduledExecutorService`的作用是什么?
ScheduledExecutorService
用于延迟执行或定期执行任务。
ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(1);
scheduledExecutor.scheduleAtFixedRate(() -> {
// 定期执行的任务
}, 0, 1, TimeUnit.SECONDS);