深度剖析Java高并发:从线程池到CAS原理,阿里面试必问系列
引言高并发是Java后端开发的核心能力也是大厂面试的重灾区。本文将从线程池核心原理、CAS无锁机制、Synchronized优化、JUC并发工具类四个维度深入剖析Java高并发的底层逻辑。一、线程池核心原理1.1 线程池为什么要用直接创建线程的问题// 每次请求都创建新线程for(inti0;i1000;i){newThread(()-{// 业务逻辑}).start();}问题线程创建和销毁开销大大量线程竞争CPU资源线程数量不可控1.2 线程池工作原理// 线程池核心参数publicThreadPoolExecutor(intcorePoolSize,// 核心线程数intmaximumPoolSize,// 最大线程数longkeepAliveTime,// 空闲线程存活时间TimeUnitunit,// 时间单位BlockingQueueRunnableworkQueue,// 任务队列ThreadFactorythreadFactory,// 线程工厂RejectedExecutionHandlerhandler// 拒绝策略)线程池执行流程任务进来 ↓ corePoolSize未满→ 创建核心线程执行 ↓ (是) 核心线程满了吗 ↓ (否) workQueue未满→ 任务加入队列等待 ↓ (是) maximumPoolSize未满→ 创建临时线程执行 ↓ (是) 执行拒绝策略1.3 七大参数详解参数含义设置建议corePoolSize核心线程数CPU密集型CPU核数1IO密集型CPU核数×2maximumPoolSize最大线程数corePoolSize × 2keepAliveTime空闲存活时间默认10msworkQueue任务队列LinkedBlockingQueue/SynchronousQueuethreadFactory线程工厂自定义线程名便于排查handler拒绝策略AbortPolicy/CallerRunsPolicy1.4 阿里面试题线程池大小怎么设置// CPU密集型任务intcorePoolSizeRuntime.getRuntime().availableProcessors()1;// IO密集型任务经验公式intcorePoolSizeRuntime.getRuntime().availableProcessors()*2;// 或者更精确的计算intcorePoolSizeRuntime.getRuntime().availableProcessors()/(1-阻塞系数)// 阻塞系数通常取0.8~0.9二、CAS无锁机制2.1 CAS是什么CASCompare And Swap是一种无锁算法它包含三个操作数内存位置 V预期原值 A新值 B// CAS语义只有当V的值等于A时才用B去更新V// 否则什么都不做返回V当前值2.2 Java中CAS的实现// AtomicInteger源码分析publicclassAtomicIntegerextendsNumber{privatestaticfinallongserialVersionUID...;// 使用Unsafe类的CAS操作privatevolatileintvalue;publicfinalbooleancompareAndSwap(intexpectedValue,intnewValue){returnunsafe.compareAndSwapInt(this,valueOffset,expectedValue,newValue);}// 乐观锁实现publicfinalintincrementAndGet(){for(;;){intcurrentget();intnextcurrent1;if(compareAndSwap(current,next)){returnnext;}}}}2.3 CAS的三大问题问题1ABA问题// 线程1读取A线程2将A改成B又改回A线程1的CAS仍会成功// 解决使用AtomicStampedReference增加版本号AtomicStampedReferenceIntegerrefnewAtomicStampedReference(1,0);ref.compareAndSet(1,2,0,1);// 带版本号的CAS问题2自旋开销大// 如果CAS失败会一直自旋消耗CPU// 解决限制自旋次数或使用LongAdderLongAddercounternewLongAdder();counter.increment();// 分散热点优于AtomicLong问题3只能保证一个变量原子性// 多个变量需要原子操作怎么办// 解决使用AtomicReferenceAtomicReferenceUseruserRefnewAtomicReference();userRef.compareAndSet(oldUser,newUser);三、Synchronized优化3.1 synchronized锁升级路径无锁 → 偏向锁 → 轻量级锁 → 重量级锁锁类型场景升级条件偏向锁单线程访问无竞争轻量级锁多线程轻度竞争短时间自旋重量级锁多线程激烈竞争自旋超过阈值3.2 锁消除publicvoidmethod(){// JIT编译时发现这个StringBuffer不会逃逸出方法外// 消除synchronized直接拼接StringBuffersbnewStringBuffer();sb.append(a).append(b);// 实际上没有锁的开销}3.3 锁粗化// 连续加锁操作JIT会合并StringBuffersbnewStringBuffer();synchronized(sb){sb.append(a);}synchronized(sb){sb.append(b);}// JIT优化为synchronized(sb){sb.append(a);sb.append(b);}四、JUC并发工具类4.1 CountDownLatch门闩// 场景等待多个线程执行完毕再执行主线程CountDownLatchlatchnewCountDownLatch(3);newThread(()-{// 任务1latch.countDown();}).start();newThread(()-{// 任务2latch.countDown();}).start();latch.await();// 阻塞直到countDown()被调用3次System.out.println(所有任务完成);4.2 CyclicBarrier循环栅栏// 场景多个线程互相等待全部到达后再执行CyclicBarrierbarriernewCyclicBarrier(3,()-{System.out.println(所有人都到了开始执行任务);});for(inti0;i3;i){newThread(()-{// 准备任务barrier.await();// 等待其他人// 执行任务}).start();}4.3 Semaphore信号量// 场景控制同时访问资源的线程数SemaphoresemaphorenewSemaphore(3);for(inti0;i10;i){newThread(()-{try{semaphore.acquire();// 获取许可证// 访问共享资源数据库连接池等semaphore.release();// 释放许可证}catch(InterruptedExceptione){e.printStackTrace();}}).start();}总结知识点面试重点线程池7大参数、执行流程、拒绝策略CAS原理、ABA问题、LongAdderSynchronized锁升级、锁消除、锁粗化JUC工具CountDownLatch/CyclicBarrier/Semaphore核心口诀线程池控资源CAS乐观无阻塞Synchronized看升级JUC工具解并发。