领先的免费Web技术教程,涵盖HTML到ASP.NET

网站首页 > 知识剖析 正文

Java多线程面试必问题:从volatile到线程池,阿里P8整理核心答案

nixiaole 2025-09-21 20:41:27 知识剖析 2 ℃

一、高频面试题全景解析

1. volatile如何保证可见性?底层原理是什么?

// 典型场景:多线程共享变量可见性问题
public class VisibilityDemo {
    // 不加volatile时,线程可能读取到旧值
    private volatile boolean flag = true;

    public void start() {
        new Thread(() -> {
            while (flag) { /* 空循环 */ }
            System.out.println("线程退出");
        }).start();
        
        new Thread(() -> {
            flag = false;
        }).start();
    }
}

核心答案

  • volatile通过内存屏障(Memory Barrier)和缓存一致性协议(如MESI)实现可见性
  • 写操作后强制刷新主内存,读操作前强制从主内存读取
  • 底层通过JVM的StoreStore、StoreLoad等屏障指令实现

2. synchronized与ReentrantLock底层实现差异

// ReentrantLock显式锁实战
public class LockDemo {
    private final ReentrantLock lock = new ReentrantLock(true); // 公平锁
    
    public void accessResource() {
        lock.lock();
        try {
            // 临界区代码
        } finally {
            lock.unlock();
        }
    }
}

核心对比

特性

synchronized

ReentrantLock

实现方式

JVM层面(monitorenter)

JDK层面(AQS)

锁类型

非公平锁

支持公平/非公平

中断响应

不支持

支持lockInterruptibly()

条件变量

单个

可创建多个Condition对象


3. 线程池参数配置黄金法则

// 阿里推荐线程池配置模板
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    5, // 核心线程数(CPU密集型建议N+1)
    10, // 最大线程数(IO密集型建议2N)
    60L, TimeUnit.SECONDS, // 保活时间
    new LinkedBlockingQueue<>(100), // 任务队列
    new ThreadFactoryBuilder().setNameFormat("order-pool-%d").build(), // 命名规范
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);

关键参数解析

  • 队列选择
    • SynchronousQueue:直接传递,适合短任务
    • LinkedBlockingQueue:无界队列,易导致OOM
    • ArrayBlockingQueue:有界队列,需合理评估容量

二、真实场景案例拆解

案例1:订单超时未支付自动关闭

// 线程安全的时间轮算法实现
public class TimeWheel {
    private final ConcurrentHashMap<Long, Order> orderMap = new ConcurrentHashMap<>();
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    public void addOrder(Order order) {
        orderMap.put(order.getId(), order);
        scheduler.schedule(() -> {
            if (order.getStatus() == UNPAID) {
                order.close();
                orderMap.remove(order.getId());
            }
        }, 30, TimeUnit.MINUTES);
    }
}

技术要点

  • 使用ConcurrentHashMap保证线程安全
  • 单线程调度避免任务竞争
  • 幂等性处理防止重复关单

案例2:秒杀系统库存扣减

// 基于CAS的乐观锁实现
public class StockService {
    private AtomicInteger stock = new AtomicInteger(100);

    public boolean reduceStock() {
        int current;
        do {
            current = stock.get();
            if (current <= 0) return false;
        } while (!stock.compareAndSet(current, current - 1));
        return true;
    }
}

优化策略

  • 分段锁降低竞争粒度
  • Redis+Lua脚本保证原子性
  • 本地缓存+异步扣减提升吞吐量

三、必知必会考点总结

  1. ThreadLocal内存泄漏根源
  • 弱引用解决Entry的Key泄漏
  • 必须手动remove()清理Value
  1. 死锁检测与预防
  • jstack生成线程快照分析
  • 统一加锁顺序避免循环等待
  1. CompletableFuture异步编排
CompletableFuture.supplyAsync(() -> getPrice())
    .thenCombineAsync(getStock(), (price, stock) -> calcTotal())
    .exceptionally(ex -> handleError());

四、面试加分技巧

  • 源码级理解:AQS的CLH队列实现、ThreadPoolExecutor的Worker机制
  • 性能调优:通过jstack分析线程阻塞点、jstat监控线程状态
  • 行业实践:美团动态线程池配置、阿里Sentinel线程隔离策略

结语:掌握这些核心要点,面试通过率提升80%!转发收藏本文,备战金九银十,助你斩获心仪Offer!

Tags:

最近发表
标签列表