一、核心原理
-
CAS(Compare and Swap)
- 机制:通过硬件指令(如
cmpxchg
)实现无锁原子操作,包含三个操作数(内存地址V、预期值A、新值B)。 - ABA问题:值从A→B→A,CAS误判未变化。解决方案:添加版本号(如
AtomicStampedReference
)。 - 应用:
AtomicInteger
、ReentrantLock
底层实现。
- 机制:通过硬件指令(如
-
AQS(AbstractQueuedSynchronizer)
- 核心结构:双向CLH队列 + volatile状态变量(
state
)。 - 实现类:
ReentrantLock
:通过state
记录重入次数。CountDownLatch
:state
表示剩余计数。
- 关键方法:
acquire()
:尝试获取资源,失败则入队阻塞。release()
:释放资源,唤醒后继节点。
- 核心结构:双向CLH队列 + volatile状态变量(
-
synchronized锁升级
- 无锁 → 偏向锁:对象头记录线程ID,减少同一线程重入开销。
- 偏向锁 → 轻量级锁:竞争时撤销偏向,通过CAS自旋获取锁。
- 轻量级锁 → 重量级锁:自旋失败后,升级为OS互斥量(Mutex),线程进入阻塞。
- 优化意义:减少直接使用重量级锁的性能损耗。
-
volatile内存屏障
- 可见性:写操作后插入
StoreStore
+StoreLoad
屏障,强制刷新主内存。 - 有序性:禁止指令重排序(通过
LoadLoad
和LoadStore
屏障)。 - 局限性:不保证复合操作原子性(如
i++
需配合synchronized
或AtomicInteger
)。
- 可见性:写操作后插入
二、线程池
-
7大参数
- corePoolSize:核心线程数(常驻)。
- maximumPoolSize:最大线程数(临时线程 = max - core)。
- keepAliveTime:非核心线程空闲存活时间。
- unit:时间单位(如
TimeUnit.SECONDS
)。 - workQueue:任务队列(
ArrayBlockingQueue
、LinkedBlockingQueue
)。 - threadFactory:自定义线程创建(如命名线程)。
- handler:拒绝策略(如
AbortPolicy
)。
-
拒绝策略
- AbortPolicy:默认策略,抛出
RejectedExecutionException
。 - CallerRunsPolicy:由提交任务的线程直接执行。
- DiscardPolicy:静默丢弃新任务。
- DiscardOldestPolicy:丢弃队列头部任务,重试提交。
- AbortPolicy:默认策略,抛出
-
动态调整核心线程数
- 方法:
executor.setCorePoolSize(newSize)
。 - 场景:根据流量高峰动态扩容/缩容,需结合监控系统(如Prometheus)。
- 方法:
三、并发容器
-
ConcurrentHashMap分段锁演进
- Java 7:分段锁(Segment),默认16段,每段独立加锁。
- Java 8:CAS +
synchronized
锁桶(Node),链表转红黑树优化查询。 - 性能对比:Java 8的锁粒度更细,并发度更高。
-
CopyOnWriteArrayList适用场景
- 原理:写时复制(复制整个数组),读操作无锁。
- 优点:读性能极高,适合读多写极少(如黑白名单)。
- 缺点:写操作开销大,数据一致性弱(最终一致)。
四、场景题:高并发订单系统设计
-
库存扣减
- 方案一:Redis原子操作
// 使用Lua脚本保证原子性 String script = "if redis.call('get', KEYS[1]) >= ARGV[1] then " + "return redis.call('decrby', KEYS[1], ARGV[1]) " + "else return -1 end"; Long result = jedis.eval(script, Collections.singletonList("stock"), 1);
- 方案二:数据库乐观锁
UPDATE product SET stock = stock - 1, version = version + 1 WHERE id = #{productId} AND version = #{oldVersion};
- 方案一:Redis原子操作
-
分布式锁
- Redis实现(RedLock):
// 加锁 String lockKey = "order_lock_" + productId; String requestId = UUID.randomUUID().toString(); Boolean locked = jedis.set(lockKey, requestId, "NX", "PX", 30000); // 解锁(Lua脚本保证原子性) String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " + "return redis.call('del', KEYS[1]) else return 0 end"; jedis.eval(script, Collections.singletonList(lockKey), requestId);
- ZooKeeper实现:创建临时有序节点,最小节点获得锁,监听前序节点释放。
- Redis实现(RedLock):
-
架构设计要点
- 限流:网关层使用令牌桶(如Redis + Lua)。
- 降级:库存预扣减后异步持久化,保证最终一致。
- 分库分表:按用户ID哈希分表,避免热点问题。
通过深入理解上述知识点,并结合实际场景设计,能够在面试中展示出扎实的并发编程能力和系统设计思维。