JDK17_JDK21并发编程小白入门:资深架构常用模式+最佳实践

📅 发布时间:2026/7/4 20:09:06 👁️ 浏览次数:
JDK17_JDK21并发编程小白入门:资深架构常用模式+最佳实践
JDK17/JDK21并发编程小白入门资深架构常用模式最佳实践通俗易懂版先跟小白说句大实话并发编程不是“炫技”是大厂开发、高并发系统比如电商秒杀、APP接口的“必备技能”也是资深架构和普通程序员的核心差距之一。很多小白一听到“并发”“多线程”就头大觉得全是复杂理论、看不懂也用不上——其实不然。这篇文章全程不用难懂的术语不搞空洞理论只讲JDK17、JDK21里最常用、最实用的并发知识梳理高企资深架构天天在用的经典模式、最佳实践还有高频踩坑点小白式拆解保证你看完能懂、上手能用。先明确一个核心前提JDK17是“稳定款”企业生产环境首选JDK21是“升级款”主打并发性能优化新项目/高并发场景首选两者的并发特性是“兼容且升级”的我们重点讲“两者都能用、资深架构必用”的内容区分开“JDK21专属优化”避免你学混。一、小白必懂并发编程到底是什么一句话讲透不用背定义举2个生活例子瞬间明白单线程你一个人做饭先洗菜→切菜→炒菜→盛饭一步做完才能做下一步效率低并发你洗菜、你对象切菜、你妈炒菜一起动手同时做不同的事最后一起完成效率翻倍。对应到编程里“单线程”就是程序一次只做一件事“并发”就是程序同时做多件事比如一个接口同时被1000个人调用程序要同时处理这1000个请求。而JDK17、JDK21做的事就是给你“提供现成的工具”让你不用自己从零写“多个人一起干活”的逻辑还能避免“多人干活乱套”比如两个人同时炒一盘菜最后炒糊这就是我们要学的“并发编程工具模式”。补充一句高企里的“高并发场景”比如秒杀、直播带货本质就是“很多人同时找程序干活”学好并发就是让程序“能扛住、不卡顿、不出错”。二、核心基础JDK17/JDK21并发编程的“3个核心工具”必懂拿来就用资深架构写并发代码从来不会“从零造轮子”全是用JDK自带的工具。这3个工具是所有并发场景的“基石”JDK17和JDK21都能用小白必须先吃透、记牢。2.1 工具1线程Thread—— 并发的“干活的人”还是用做饭的例子线程就是“干活的人”一个线程一个干活的人。重点讲小白能懂的核心点复杂的底层跳过JDK17及之前我们用的是“普通线程”也叫OS线程—— 就像“正式员工”每个员工线程要占一个工位内存工位成本高每个线程默认占1MB内存公司JVM最多能雇几千个“正式员工”多了就没工位OOM报错JDK21专属优化新增“虚拟线程”—— 就像“临时工”不用固定工位内存占用只有几十KB还能动态调整公司JVM能雇百万级、千万级的“临时工”成本极低。小白重点记什么时候用普通线程什么时候用虚拟线程资深架构的选型逻辑直接抄用普通线程JDK17/JDK21都能用干活时间长、不闲着比如计算100万条数据、复杂算法—— 类似“正式员工干核心重活”用虚拟线程仅JDK21能用干活时间短、经常等比如调用其他接口、查数据库、读文件—— 类似“临时工干杂活等的时候可以去干别的”比如1000个人同时查订单线程大部分时间在等数据库响应用虚拟线程性价比极高。举个小白能看懂的代码例子极简不用纠结细节看思路// JDK17 普通线程正式员工ThreadthreadnewThread(()-{// 这里写要干的活比如计算数据System.out.println(正式员工干活计算数据);});thread.start();// 让员工开始干活// JDK21 虚拟线程临时工写法更简单Thread.startVirtualThread(()-{// 这里写要干的活比如查数据库System.out.println(临时工干活查数据库);});2.2 工具2锁Lock—— 避免“干活乱套”的规则还是做饭例子如果两个人同时炒一盘菜同一个资源必然会炒糊、乱套。锁就是“规定谁先炒、谁后炒”的规则保证同一时间只有一个人线程能碰这盘菜资源。小白重点记JDK17/JDK21里资深架构最常用的2种锁不用学其他的吃透这2种就够了1ReentrantLock重入锁—— 灵活的“手动锁”JDK17/JDK21都能用就像“厨房的门钥匙”谁拿到钥匙谁就能进厨房炒菜其他人只能等。特点是“灵活”能自己控制“什么时候拿钥匙、什么时候还钥匙”适合复杂场景。资深架构的最佳实践小白直接抄代码不用改// 1. 先创建一把锁相当于厨房钥匙LocklocknewReentrantLock();// 2. 干活的时候先拿锁干完还锁避免别人一直等try{lock.lock();// 拿钥匙进入厨房// 这里写要干的活比如操作同一个变量、修改同一条数据库数据System.out.println(拿到锁开始干活别人不能碰);}finally{lock.unlock();// 还钥匙离开厨房必须写在finally里防止忘还钥匙死锁}小白避坑点高频踩坑必看千万别忘写unlock()如果不写拿到钥匙的线程崩溃了钥匙就永远不还了其他人永远进不去厨房死锁程序直接卡住unlock()必须写在finally里不管干活成功还是失败都能保证钥匙归还。2synchronized同步锁—— 简单的“自动锁”JDK17/JDK21都能用就像“厨房的自动门”有人进去线程干活门就自动锁上其他人等人出来线程干完门自动解锁不用手动控制。特点是“简单”适合简单场景不用写复杂的拿锁、还锁逻辑。资深架构的最佳实践小白直接抄// 方式1加在方法上整个方法都是“厨房”进去就锁门publicsynchronizedvoidcook(){// 干活逻辑比如炒一盘菜System.out.println(自动锁开始炒菜别人不能进);}// 方式2加在代码块上只有代码块是“厨房”更灵活publicvoidcook(){// 其他不用锁的逻辑比如准备盘子synchronized(this){// 要锁的逻辑比如炒菜System.out.println(自动锁开始炒菜别人不能进);}}小白选型技巧资深架构常用简单场景比如单个方法、简单变量操作用synchronized不用写多余代码不容易出错复杂场景比如需要超时重试、中断等待、多条件判断用ReentrantLock更灵活。2.3 工具3线程池ThreadPool—— 高效“管理干活的人”JDK17/JDK21都能用还是做饭例子如果每次做饭都要重新找一个人创建线程、教他怎么干初始化线程干完再让他走销毁线程效率极低。线程池就是“固定的团队”—— 公司JVM提前雇好一批人线程有活了直接分配干完活不用走等着下一个活不用每次都创建、销毁效率翻倍。小白重点记资深架构从来不会“每次用线程都新建一个”全是用线程池因为创建/销毁线程的成本太高高并发场景下会拖垮程序。JDK17/JDK21最常用的线程池小白直接抄代码不用自己配置// 1. 创建线程池固定10个“员工”适合大部分普通场景ExecutorServicethreadPoolExecutors.newFixedThreadPool(10);// 2. 给线程池分配活提交任务for(inti0;i100;i){threadPool.submit(()-{// 要干的活比如处理一个用户请求、查一次数据库System.out.println(线程池里的员工干活中);});}// 3. 程序结束时关闭线程池不然程序不会停threadPool.shutdown();// 优雅关闭等所有活干完再关闭// threadPool.shutdownNow(); // 强制关闭不管活有没有干完立即停止慎用资深架构的核心配置技巧小白不用死记理解即可线程池大小多少个员工普通IO场景查数据库、调接口设置为 CPU核心数 * 2CPU密集场景计算数据设置为 CPU核心数 1不用自己手动创建线程池比如new ThreadPoolExecutor用Executors提供的现成方法newFixedThreadPool、newCachedThreadPool简单且不易出错JDK21优化线程池支持直接提交“虚拟线程”不用手动创建虚拟线程写法更简单小白了解即可后续讲模式时再详细说。三、重点中的重点高企资深架构常用的“5个并发经典模式”JDK17/JDK21实战版这部分是核心中的核心—— 资深架构写并发代码全是套用这些模式不用自己瞎琢磨小白学会这些就能应对80%的企业并发场景秒杀、接口高并发、数据批量处理等。所有模式都结合JDK17/JDK21特性用小白能懂的语言拆解附上极简实战代码直接抄还有最佳实践。模式1单例模式并发安全版—— 全局只有一个“工具”JDK17/JDK21必用场景举例程序里的“日志工具”“数据库连接工具”我们希望整个程序只有一个实例比如只有一个日志工具不然日志会乱套这就是单例模式。小白重点单例模式必须保证“并发安全”—— 不能多个线程同时创建出多个实例比如两个线程同时创建日志工具最后有两个日志工具日志混乱。资深架构最常用的写法JDK17/JDK21通用并发安全直接抄// 单例模式全局只有一个实例publicclassLogUtil{// 1. 私有构造方法禁止别人手动创建实例privateLogUtil(){}// 2. 静态内部类懒加载只有用到的时候才创建实例privatestaticclassLogUtilHolder{// 唯一实例privatestaticfinalLogUtilINSTANCEnewLogUtil();}// 3. 提供公共方法获取实例并发安全JVM自动保证publicstaticLogUtilgetInstance(){returnLogUtilHolder.INSTANCE;}// 业务方法写日志publicvoidlog(Stringmessage){System.out.println(message);}}最佳实践小白必记不用学“饿汉式”“双重检查锁”就用这种“静态内部类”写法—— 简单、并发安全、懒加载不用的时候不占内存资深架构首选JDK17可以用“密封类sealed”修饰LogUtil禁止别人继承更安全前文讲过密封类这里直接套用。模式2生产者-消费者模式 —— 解耦“干活的人”JDK17/JDK21必用场景举例电商秒杀中“用户下单”是生产者产生订单任务“订单处理”是消费者处理订单任务或者“日志收集”是生产者产生日志“日志写入文件”是消费者处理日志。核心价值让生产者和消费者“互不干扰”—— 生产者只管产生任务消费者只管处理任务中间用一个“任务队列”衔接就算生产者产生任务太快消费者也能慢慢处理不会拖垮生产者比如秒杀时1000个人同时下单订单处理不过来就先存到队列里慢慢处理。资深架构实战写法JDK17/JDK21通用直接抄publicclassProducerConsumerDemo{// 1. 任务队列衔接生产者和消费者存订单任务privatestaticfinalBlockingQueueStringtaskQueuenewArrayBlockingQueue(100);publicstaticvoidmain(String[]args){// 2. 生产者线程池3个生产者负责产生订单ExecutorServiceproducerPoolExecutors.newFixedThreadPool(3);// 3. 消费者线程池5个消费者负责处理订单ExecutorServiceconsumerPoolExecutors.newFixedThreadPool(5);// 生产者产生任务模拟100个用户下单for(inti0;i100;i){intorderIdi;producerPool.submit(()-{try{Stringtask订单orderId;taskQueue.put(task);// 把订单放到队列里System.out.println(生产者产生task);}catch(InterruptedExceptione){Thread.currentThread().interrupt();}});}// 消费者处理任务for(inti0;i5;i){consumerPool.submit(()-{while(true){try{StringtasktaskQueue.take();// 从队列里拿订单没有就等System.out.println(消费者处理task);// 模拟处理订单的耗时比如查库存、扣库存Thread.sleep(100);}catch(InterruptedExceptione){Thread.currentThread().interrupt();break;}}});}// 关闭线程池实际开发中程序结束时关闭producerPool.shutdown();consumerPool.shutdown();}}最佳实践小白必记任务队列用BlockingQueueJDK自带不用自己写队列—— 它自带“阻塞”功能没有任务时消费者会自动等不用手动写等待逻辑任务满了生产者会自动等避免出错生产者和消费者用线程池不用单个线程—— 高并发场景下单个线程扛不住JDK21优化可以把消费者线程换成“虚拟线程”处理更多任务写法更简单把consumerPool换成虚拟线程池即可。模式3Future模式 —— 异步“拿结果”JDK17/JDK21必用场景举例你去餐厅吃饭点完菜提交任务不用一直等菜上桌不用一直阻塞线程可以玩手机线程干别的活菜做好了服务员会叫你拿到任务结果—— 这就是Future模式。核心价值避免“线程阻塞”提高效率—— 比如一个接口需要同时查“用户信息”“订单信息”“优惠券信息”不用等查完用户信息再查订单信息而是同时查最后汇总结果接口响应速度翻倍。资深架构实战写法JDK17/JDK21通用直接抄publicclassFutureDemo{publicstaticvoidmain(String[]args)throwsExecutionException,InterruptedException{// 1. 创建线程池ExecutorServicethreadPoolExecutors.newFixedThreadPool(3);// 2. 异步查用户信息提交任务不用等结果直接返回FutureFutureStringuserFuturethreadPool.submit(()-{Thread.sleep(500);// 模拟查数据库耗时return用户信息张三ID1001;});// 3. 异步查订单信息同时执行不用等用户信息查完FutureStringorderFuturethreadPool.submit(()-{Thread.sleep(300);// 模拟查数据库耗时return订单信息订单ID2001金额100元;});// 4. 干别的活比如查优惠券信息不用等上面两个结果System.out.println(干别的活查优惠券信息);Thread.sleep(200);// 5. 拿到异步任务的结果如果没做好会等做好再拿StringuserInfouserFuture.get();// 拿到用户信息StringorderInfoorderFuture.get();// 拿到订单信息// 6. 汇总结果System.out.println(汇总结果userInfoorderInfo);// 关闭线程池threadPool.shutdown();}}最佳实践小白必记用Future.get()拿结果时会“阻塞线程”—— 所以一定要先干别的活最后再拿结果不然就失去了异步的意义如果不想一直等可以用Future.get(1, TimeUnit.SECONDS)—— 设置超时时间比如1秒超过1秒没拿到结果就抛出异常避免线程一直阻塞JDK21优化新增FutureTask的简化写法不用手动提交线程池直接用虚拟线程执行代码更简洁小白了解即可重点掌握上面的通用写法。模式4结构化并发模式 —— 管理“一组相关任务”JDK21专属资深架构新宠场景举例一个接口需要“查用户信息查订单信息查优惠券信息”这三个任务是“相关的”—— 只要有一个任务失败比如查用户信息失败另外两个任务就不用执行了还要一起取消避免浪费资源。核心价值解决“多任务混乱”的问题—— 之前用Future模式多个任务之间互不关联一个失败其他还在执行浪费资源结构化并发能把一组相关任务“绑在一起”统一管理、统一取消、统一处理结果。资深架构实战写法仅JDK21能用直接抄publicclassStructuredConcurrentDemo{publicstaticvoidmain(String[]args)throwsExecutionException,InterruptedException{// 1. 创建结构化任务作用域绑定一组相关任务try(varscopenewStructuredTaskScope.ShutdownOnFailure()){// 2. 提交三个相关任务查用户、查订单、查优惠券FutureStringuserFuturescope.fork(()-{Thread.sleep(500);// 模拟任务失败如果用户ID错误抛出异常// throw new RuntimeException(查用户信息失败);return用户信息张三;});FutureStringorderFuturescope.fork(()-{Thread.sleep(300);return订单信息100元;});FutureStringcouponFuturescope.fork(()-{Thread.sleep(200);return优惠券信息10元;});// 3. 等待所有任务完成如果有一个失败其他任务会被自动取消scope.join();// 4. 拿到所有任务结果StringuserInfouserFuture.resultNow();StringorderInfoorderFuture.resultNow();StringcouponInfocouponFuture.resultNow();System.out.println(汇总结果userInfoorderInfocouponInfo);}// 作用域自动关闭所有任务会被自动清理不用手动关闭线程池}}最佳实践小白必记结构化并发是JDK21专属JDK17不能用—— 新项目、高并发接口优先用这种模式比Future模式更简洁、更安全核心是“ShutdownOnFailure()”—— 意思是“一个任务失败所有任务都取消”适合“多个任务必须同时成功”的场景比如下单时查库存、扣库存、减优惠券必须都成功有一个失败就取消不用手动创建线程池、关闭线程池作用域会自动管理减少出错概率。模式5虚拟线程池模式 —— 百万级并发的“秘密武器”JDK21专属高并发首选场景举例电商秒杀、APP首页接口同时有10万、100万用户请求用普通线程池最多只能处理几千个请求会直接拖垮程序用虚拟线程池能轻松处理百万级请求且内存占用极低。核心价值JDK21的“杀手锏”—— 不用手动创建虚拟线程直接用虚拟线程池写法和普通线程池几乎一样就能实现“百万级并发”不用改太多代码。资深架构实战写法仅JDK21能用直接抄秒杀场景首选publicclassVirtualThreadPoolDemo{publicstaticvoidmain(String[]args){// 1. 创建虚拟线程池JDK21新增写法和普通线程池几乎一样ExecutorServicevirtualThreadPoolExecutors.newVirtualThreadPerTaskExecutor();// 2. 提交100万个任务模拟百万级用户请求for(inti0;i1000000;i){intrequestIdi;virtualThreadPool.submit(()-{// 模拟接口处理逻辑查数据库、调下游接口try{Thread.sleep(10);// 模拟耗时System.out.println(处理请求requestId);}catch(InterruptedExceptione){Thread.currentThread().interrupt();}});}// 3. 关闭虚拟线程池virtualThreadPool.shutdown();}}最佳实践小白必记虚拟线程池只能用在JDK21且只适合“IO密集场景”查数据库、调接口、读文件CPU密集场景用普通线程池不然性能会下降创建虚拟线程池只用Executors.newVirtualThreadPerTaskExecutor()不用自己配置简单且高效百万级并发场景秒杀、直播优先用虚拟线程池不用考虑内存溢出—— 虚拟线程内存占用极低100万个虚拟线程内存占用只有几十MB。四、高频核心原理小白能懂版不用背理解即可资深架构面试时经常会问这些原理但不用背复杂术语理解下面的“小白版解释”就能应对面试也能更好地用对并发工具。4.1 并发安全的核心原理可见性、原子性、有序性小白版可见性一个线程修改了数据其他线程能立即看到—— 比如你修改了订单状态其他线程能立即看到修改后的状态不然会出现“一个线程以为订单没支付另一个线程以为已经支付”的错误原子性一个操作要么全部完成要么全部不完成不能中途打断—— 比如扣库存“库存从100减到99”要么完成要么不完成不能出现“库存变成99.5”或者“扣了库存但没保存”的情况有序性程序执行的顺序和我们写的顺序一致—— 比如你写了“先查库存再扣库存”程序不能先扣库存再查库存不然会出现超卖。小白重点我们前面学的锁synchronized、ReentrantLock、线程池、并发模式本质都是为了“保证这三个特性”避免并发安全问题—— 不用深究底层只要知道“用对这些工具就能保证并发安全”即可。4.2 死锁的核心原理小白版避坑关键死锁两个线程“互相等对方的钥匙”谁也不让谁最后都卡住程序崩溃—— 比如线程A拿着钥匙1等着线程B的钥匙2线程B拿着钥匙2等着线程A的钥匙1两人一直等永远干不了活。小白避坑只要记住“三个避免”就不会出现死锁避免一个线程拿多把锁避免锁的顺序混乱比如线程A先拿钥匙1再拿钥匙2线程B也必须先拿钥匙1再拿钥匙2避免忘记归还锁unlock()写在finally里。4.3 JDK21并发优化的核心原理小白版JDK21的并发优化本质就是“降低成本、提高效率”不用背底层记住3个核心优化即可虚拟线程降低线程的内存成本从“每个线程1MB”降到“每个线程几十KB”支持百万级并发结构化并发统一管理相关任务避免资源浪费简化多任务并发的写法虚拟线程池不用手动创建虚拟线程直接用线程池的写法就能实现百万级并发降低学习和使用成本。五、实用注意事项小白必看高频踩坑点汇总这部分是资深架构多年踩坑总结的“经验之谈”小白看完能避免90%的并发编程错误少走很多弯路。5.1 通用注意事项JDK17/JDK21都适用永远不要手动创建线程new Thread()全用线程池—— 手动创建/销毁线程成本太高高并发场景下会拖垮程序锁的范围越小越好—— 比如只锁“炒菜”的逻辑不锁“准备盘子”的逻辑提高并发效率避免在锁里面做“耗时操作”比如查数据库、调接口—— 不然其他线程会一直等并发效率极低线程池一定要关闭—— 不用的时候必须调用shutdown()不然程序不会正常停止不要用ThreadLocal存储“共享数据”—— ThreadLocal是“每个线程单独存储数据”共享数据存在里面其他线程看不到会出现数据不一致。5.2 JDK17专属注意事项JDK17没有虚拟线程高并发IO场景用普通线程池线程池大小设置为CPU核心数*2用synchronized锁方法时不要用“静态方法锁”synchronized static—— 会锁整个类并发效率极低单例模式优先用“静态内部类”写法不用双重检查锁容易出错。5.3 JDK21专属注意事项虚拟线程只适合“IO密集场景”CPU密集场景计算数据还是用普通线程池不然性能会下降结构化并发的作用域必须用try-with-resources写法try (var scope …)不然会出现资源泄漏虚拟线程池newVirtualThreadPerTaskExecutor()不用手动设置线程池大小JVM会自动管理JDK21的并发特性和JDK17兼容—— 之前写的JDK17并发代码升级到JDK21后不用修改就能直接运行。六、最后总结小白必看划重点并发编程不用怕核心就是“用对JDK自带的工具”—— 线程普通虚拟、锁synchronizedReentrantLock、线程池再套用5个经典模式就能应对80%的企业场景JDK17和JDK21的选择老项目、稳定优先用JDK17新项目、高并发IO场景秒杀、接口用JDK21优先用虚拟线程和结构化并发小白学习顺序先吃透3个核心工具 → 再套用5个经典模式 → 最后记住注意事项避坑即可不用深究复杂底层资深架构的核心思路“不重复造轮子、优先用JDK原生工具、简化代码、保证并发安全”—— 我们学的就是这套思路。最后提醒并发编程的核心是“实践”把上面的代码抄下来运行一遍修改一下参数比如线程池大小、任务数量看看效果慢慢就懂了比背理论有用10倍。