面试题答案
一键面试优化多线程业务场景性能方案
- 减少锁竞争:
- 锁粒度控制:避免对整个业务逻辑使用粗粒度锁,尽量使用细粒度锁。例如,如果不同的Atomic类对象操作是相互独立的,为每个Atomic对象或相关的一组操作设置单独的锁,而不是一个全局锁。这样可以减少线程等待锁的时间,提高并发性能。
- 无锁数据结构:对于一些可以使用无锁数据结构的场景,尽量采用。如
ConcurrentHashMap
在多线程环境下比普通HashMap
更高效,因为它采用了分段锁机制,减少了锁竞争。
- 线程池优化:
- 合理配置线程池参数:根据业务场景和硬件资源,合理设置线程池的核心线程数、最大线程数、队列容量等参数。例如,对于I/O密集型任务,可以适当增加线程数;对于CPU密集型任务,线程数不宜过多,一般设置为CPU核心数 + 1,以避免过多的线程上下文切换开销。
- 使用合适的线程池类型:如
CachedThreadPool
适用于执行大量短期异步任务;FixedThreadPool
适用于控制并发线程数;ScheduledThreadPool
适用于需要定时执行任务的场景。选择合适的线程池类型有助于提高性能。
- 缓存与预计算:
- 结果缓存:对于一些计算成本较高且结果不经常变化的Atomic类操作结果,可以进行缓存。例如,使用
Guava Cache
来缓存计算结果,当相同的操作再次执行时,直接从缓存中获取结果,减少重复计算的开销。 - 预计算:在系统空闲时,对一些可能会频繁使用的Atomic类操作结果进行预计算。例如,对于一些复杂的数值计算,可以提前计算好一部分中间结果,在实际业务操作时直接使用,提高操作速度。
- 结果缓存:对于一些计算成本较高且结果不经常变化的Atomic类操作结果,可以进行缓存。例如,使用
拓展Atomic类满足特定原子操作需求
- 继承Atomic类并扩展方法:
- 示例:假设业务中有原子的“加并返回结果,如果结果大于某个阈值则执行特定操作”的需求。可以继承
AtomicInteger
类,如下:
- 示例:假设业务中有原子的“加并返回结果,如果结果大于某个阈值则执行特定操作”的需求。可以继承
class CustomAtomicInteger extends AtomicInteger {
public int addAndCheckThreshold(int delta, int threshold) {
int result = addAndGet(delta);
if (result > threshold) {
// 执行特定操作
System.out.println("Result exceeds threshold, performing specific operation.");
}
return result;
}
}
- 使用
Unsafe
类实现自定义原子操作:- 原理:
Unsafe
类提供了底层的原子操作方法,通过它可以实现更复杂的原子操作。但使用Unsafe
类需要谨慎,因为它可以直接操作内存,可能会导致内存安全问题。 - 示例:
- 原理:
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class CustomAtomicLong {
private static final Unsafe unsafe;
private static final long valueOffset;
private volatile long value;
static {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
unsafe = (Unsafe) theUnsafe.get(null);
valueOffset = unsafe.objectFieldOffset(CustomAtomicLong.class.getDeclaredField("value"));
} catch (Exception e) {
throw new Error(e);
}
}
public CustomAtomicLong(long initialValue) {
value = initialValue;
}
public long customCompareAndSwap(long expect, long update) {
if (unsafe.compareAndSwapLong(this, valueOffset, expect, update)) {
return update;
}
return get();
}
}
这里通过Unsafe
类实现了一个自定义的比较并交换操作,返回最终的值。在实际使用中,可以根据业务需求实现更复杂的原子操作。