Qwen3VL开源图文多模态大模型
2026/1/6 22:07:26
场景:电商系统的订单确认流程,需要处理三个核心资源:
@ServicepublicclassOrderService{@AutowiredprivateRedissonClientredissonClient;@AutowiredprivateInventoryServiceinventoryService;@AutowiredprivatePaymentServicepaymentService;/** * 确认订单(路径1:先锁订单,再锁库存,最后锁支付) */publicvoidconfirmOrder(StringorderId,StringproductId,StringuserId){// 1. 锁定订单RLockorderLock=redissonClient.getLock("order:lock:"+orderId);orderLock.lock();// 线程A持有订单锁try{// 2. 锁定库存RLockinventoryLock=redissonClient.getLock("inventory:lock:"+productId);inventoryLock.lock();// 线程A持有库存锁try{// 3. 锁定支付RLockpaymentLock=redissonClient.getLock("payment:lock:"+userId);paymentLock.lock();// 线程A请求支付锁try{// 业务逻辑:确认订单、扣减库存、创建支付记录doConfirmOrder(orderId,productId,userId);}finally{paymentLock.unlock();}}finally{inventoryLock.unlock();}}finally{orderLock.unlock();}}/** * 快速确认订单(路径2:先锁支付,再锁库存,最后锁订单) */publicvoidquickConfirmOrder(StringorderId,StringproductId,StringuserId){// 1. 锁定支付(与confirmOrder顺序不同)RLockpaymentLock=redissonClient.getLock("payment:lock:"+userId);paymentLock.lock();// 线程B持有支付锁try{// 2. 锁定库存RLockinventoryLock=redissonClient.getLock("inventory:lock:"+productId);inventoryLock.lock();// 线程B持有库存锁try{// 3. 锁定订单(与confirmOrder顺序不同)RLockorderLock=redissonClient.getLock("order:lock:"+orderId);orderLock.lock();// 线程B请求订单锁try{// 业务逻辑:快速确认订单、扣减库存、创建支付记录doQuickConfirmOrder(orderId,productId,userId);}finally{orderLock.unlock();}}finally{inventoryLock.unlock();}}finally{paymentLock.unlock();}}// 其他方法...}confirmOrder()方法quickConfirmOrder()方法order_123product_456user_789| 时间点 | 线程A | 线程B | 资源状态 |
|---|---|---|---|
| T0 | 调用confirmOrder("order_123", "product_456", "user_789") | 调用quickConfirmOrder("order_123", "product_456", "user_789") | 所有锁都未被持有 |
| T1 | 获取order:lock:order_123(成功) | 订单锁被线程A持有 | |
| T2 | 获取payment:lock:user_789(成功) | 订单锁被A持有,支付锁被B持有 | |
| T3 | 获取inventory:lock:product_456(成功) | 订单锁被A持有,支付锁被B持有,库存锁被A持有 | |
| T4 | 获取inventory:lock:product_456(等待中…) | 线程B等待库存锁 | |
| T5 | 获取payment:lock:user_789(等待中…) | 线程A等待支付锁,线程B等待库存锁 | |
| T6+ | 无限等待支付锁 | 无限等待库存锁 | 死锁发生! |
| 现象 | 影响 |
|---|---|
| 线程A状态 | 卡在paymentLock.lock()处,无法继续执行 |
| 线程B状态 | 卡在inventoryLock.lock()处,无法继续执行 |
| 资源状态 | 订单锁、库存锁被A持有;支付锁被B持有 |
| 系统表现 | 两个订单请求都无法完成,超时后返回错误 |
| 监控表现 | 线程池线程逐渐耗尽,系统响应变慢 |
| 条件 | 具体表现 |
|---|---|
| 互斥条件 | 每个锁只能被一个线程持有 |
| 请求与保持条件 | 线程A持有订单锁和库存锁,同时请求支付锁;线程B持有支付锁,同时请求库存锁 |
| 不剥夺条件 | 锁不能被强制剥夺,只能由持有线程主动释放 |
| 循环等待条件 | 线程A → 支付锁(被B持有);线程B → 库存锁(被A持有),形成循环等待链 |
confirmOrder()和quickConfirmOrder()两个方法的锁获取顺序不同lock()而非tryLock(),导致无限等待核心原则:所有线程必须按照相同的顺序获取锁
@ServicepublicclassOrderService{// 定义全局锁顺序:订单锁 → 库存锁 → 支付锁privatestaticfinalList<String>LOCK_ORDER=Arrays.asList("order:lock:","inventory:lock:","payment:lock:");/** * 确认订单(统一锁顺序) */publicvoidconfirmOrder(StringorderId,StringproductId,StringuserId){// 1. 收集所有需要的锁List<String>lockKeys=Arrays.asList("order:lock:"+orderId,"inventory:lock:"+productId,"payment:lock:"+userId);// 2. 按统一顺序排序锁List<String>sortedLockKeys=sortLocks(lockKeys);// 3. 按顺序获取锁List<RLock>acquiredLocks=newArrayList<>();try{for(StringlockKey:sortedLockKeys){RLocklock=redissonClient.getLock(lockKey);lock.lock();acquiredLocks.add(lock);}// 4. 执行业务逻辑doConfirmOrder(orderId,productId,userId);}finally{// 5. 按相反顺序释放锁Collections.reverse(acquiredLocks);for(RLocklock:acquiredLocks){lock.unlock();}}}/** * 快速确认订单(同样的锁顺序) */publicvoidquickConfirmOrder(StringorderId,StringproductId,StringuserId){// 使用完全相同的锁顺序,避免死锁confirmOrder(orderId,productId,userId);}/** * 按预定义顺序排序锁 */privateList<String>sortLocks(List<String>lockKeys){returnlockKeys.stream().sorted(Comparator.comparing(key->{// 根据锁前缀获取排序值for(inti=0;i<LOCK_ORDER.size();i++){if(key.startsWith(LOCK_ORDER.get(i))){returni;}}returnInteger.MAX_VALUE;})).collect(Collectors.toList());}}tryLock替代lock核心原则:避免无限等待,设置合理的超时时间
publicvoidconfirmOrder(StringorderId,StringproductId,StringuserId){RLockorderLock=redissonClient.getLock("order:lock:"+orderId);RLockinventoryLock=redissonClient.getLock("inventory:lock:"+productId);RLockpaymentLock=redissonClient.getLock("payment:lock:"+userId);try{// 尝试获取订单锁,最多等待3秒if(!orderLock.tryLock(3,TimeUnit.SECONDS)){thrownewRuntimeException("获取订单锁失败");}try{// 尝试获取库存锁,最多等待3秒if(!inventoryLock.tryLock(3,TimeUnit.SECONDS)){thrownewRuntimeException("获取库存锁失败");}try{// 尝试获取支付锁,最多等待3秒if(!paymentLock.tryLock(3,TimeUnit.SECONDS)){thrownewRuntimeException("获取支付锁失败");}try{doConfirmOrder(orderId,productId,userId);}finally{paymentLock.unlock();}}finally{inventoryLock.unlock();}}finally{orderLock.unlock();}}catch(InterruptedExceptione){Thread.currentThread().interrupt();thrownewRuntimeException("获取锁被中断");}}核心原则:最小化锁的使用,避免嵌套锁
@ServicepublicclassOrderService{/** * 优化后:减少锁的嵌套,降低死锁风险 */publicvoidconfirmOrder(StringorderId,StringproductId,StringuserId){// 1. 先检查库存(无锁,快速失败)if(!inventoryService.checkInventory(productId)){thrownewRuntimeException("库存不足");}// 2. 锁定订单(最核心的锁)RLockorderLock=redissonClient.getLock("order:lock:"+orderId);try{if(!orderLock.tryLock(5,30,TimeUnit.SECONDS)){thrownewRuntimeException("获取订单锁失败");}// 3. 再次检查库存(双重检查,防止并发更新)if(!inventoryService.checkInventory(productId)){thrownewRuntimeException("库存不足");}// 4. 扣减库存(原子操作,数据库乐观锁)inventoryService.deductInventory(productId);// 5. 创建支付记录(幂等设计,无需锁)paymentService.createPaymentRecord(orderId,userId);// 6. 确认订单doConfirmOrder(orderId,productId,userId);}catch(InterruptedExceptione){Thread.currentThread().interrupt();thrownewRuntimeException("获取锁被中断");}finally{orderLock.unlock();}}}| 工具 | 用途 | 关键指标 |
|---|---|---|
| JMX | 监控JVM线程状态 | 线程数量、阻塞线程数、死锁检测 |
| SkyWalking | 分布式链路追踪 | 慢调用、超时调用、异常调用 |
| Prometheus + Grafana | 系统监控 | 线程池使用率、响应时间、错误率 |
| Redisson监控 | 分布式锁监控 | 锁获取次数、锁等待时间、锁持有时间 |
# 1. 查看JVM线程状态,检测死锁jstack-l<PID>|grep-A20"Found one Java-level deadlock"# 2. 查看线程详情jstack<PID>>jstack.txt# 分析jstack.txt文件,寻找BLOCKED状态的线程# 3. 使用VisualVM图形化工具jvisualvm# 启动VisualVM,连接到JVM进程,查看线程状态死锁的本质是资源的无序竞争+无限等待。
| 最佳实践 | 效果 |
|---|---|
| ✅统一锁获取顺序 | 打破循环等待条件 |
✅使用tryLock替代lock | 避免无限等待 |
| ✅最小化锁持有时间 | 减少死锁发生概率 |
| ✅减少锁的嵌套 | 降低死锁复杂度 |
| ✅实现幂等设计 | 减少对锁的依赖 |
| ✅定期检测死锁 | 及时发现和处理死锁 |
在库存扣减等核心业务场景中:
tryLock参数,避免无限等待通过以上措施,可以有效避免真实业务场景中的死锁问题,确保系统的高可用性和可靠性。