杂项4

简介: 本内容涵盖Java中Lambda表达式对变量的final要求、锁机制中的synchronized使用注意事项、分布式锁与悲观锁的应用场景对比,以及Docker镜像文件(.tar)的正确处理方式。重点解析了多线程与多实例环境下资源竞争的解决方案,并提供代码示例和决策依据,适用于并发编程与微服务架构开发。

lambda式中对于变量要求是final的(不可被修改)(无法理解)

就是据变量必须是未进行修改的,比如

class Example {
    private Long instanceId; // 实例变量 - 可在 Lambda 中修改
    private static Long staticId; // 静态变量 - 可在 Lambda 中修改
    
    void process(Long paramId) { // 方法参数 - 隐式 final
        Long localId = null; // 局部变量 - 受限制
        
        localId = 123L; // 修改局部变量
        
        // Lambda 表达式
        Runnable task = () -> {
            instanceId = 456L; // ✅ 允许修改实例变量
            staticId = 789L; // ✅ 允许修改静态变量
            // localId = 999L; // ❌ 禁止修改局部变量
            // paramId = 000L; // ❌ 禁止修改方法参数
        };
    }
}
  1. 依赖 ≠ 加载
    引入模块只保证代码在类路径
  2. spring.factories = 加载门票
    决定哪些配置类会被考虑
  3. 条件注解 = 安全阀
    控制配置类是否真正生效
  4. 缺少条件注解 = 定时炸弹
    当类依赖缺失时必然爆炸

通过正确使用条件注解,可以确保:

  • MVC 配置只在传统 Web 应用生效
  • WebFlux 配置只在网关生效
  • 通用组件在所有环境可用
  • 各微服务技术栈和平共处

.taz文件使用的方式

你上传的 .tar 文件是 docker save 创建的,它是一个封装了完整 Docker 镜像结构(多层+元数据+标签)的特殊归档文件。它的目的是分发和备份整个 Docker 镜像

  • tar -xzvf (解压缩): 适用于普通的文件或源代码压缩包,目的是获取里面的文件进行操作。
  • docker load唯一正确处理 docker save 生成的 .tar 文件的方法。它的目的是将封装好的完整镜像导入到 Docker 引擎,使其立即可用于运行容器。解压这个特定的 .tar 文件会破坏其结构,导致 Docker 无法识别和使用它。


对于锁用户id的问题

示例    Long id

使用synchronized  必须要是对象,所以必须是包装类型,不能是long类型

synchronized (id)会存在常量池的问题,如果超过,对于Long类型,如果值在-128到127之间(默认情况下),会使用缓存(即同一个值返回同一个对象),但是超出这个范围,每次new Long()会创建新的对象。

- 例如:
Long a = 100L; // 在缓存范围内,同一个对象 Long b = 100L; 
// a == b 为true 
Long c = 200L; Long d = 200L;
// c == d 为false(因为200超出了缓存范围)

超出范围会导致锁失效(不同的对象)

直接使用userId.toString()也是不行,每次的对象都不同?? 导致无法锁住

userId.intern() 不行(intern()是string特有的方法)

解决方案:`userId.toString().intern()` 可以确保对于相同的用户id字符串,`intern()` 方法返回的是字符串常量池中的同一个字符串对象。这样,无论有多少个线程,只要用户id相同,它们都会锁定在同一个字符串对象上。(一种解决方案)

悲观锁针对单资源(如数据库行)的竞争,无论单线程或多实例;
分布式锁针对跨系统资源的全局协调,核心是多实例/多进程的互斥管理。

单例,多实例

  1. 看竞争资源:
  • 资源是数据库里的一行数据? -> 优先考虑数据库悲观锁 (行锁)
  • 资源是一个文件、一个外部API配额、一段复杂业务逻辑、或者需要跨库操作? -> 必须用分布式锁
  1. 看协调范围:
  • 只需要保证单个数据库写操作的原子性和隔离性? -> 数据库悲观锁足够
  • 需要保证一系列操作 (可能跨多个SQL、服务、资源) 作为一个整体原子执行? -> 必须用分布式锁
  1. 多实例 vs 数据库:
  • 多个实例操作同一个数据库 -> 对于纯粹且简单的数据库操作竞争,悲观锁 (行锁) 是首选高效方案
  • 多个实例操作不同数据库 -> 悲观锁失效,必须用分布式锁
  • 多个实例操作同一个数据库,但竞争涉及复杂逻辑链 -> 必须用分布式锁

简单决策树(简化版):

text

需要协调多个实例访问共享资源吗?
  |
  |--> 资源是数据库里的一行/表,且操作是简单直接的数据库操作 (如单个UPDATE)?
        |
        |--> YES: 使用数据库悲观锁 (行锁/表锁) -> 高效,原生支持。
        |
        |--> NO: (资源是文件/API/复杂逻辑链/跨库操作)
               |
               |--> 使用分布式锁 -> 跨实例协调,保护任意资源或逻辑。

维度

适合行锁的场景

需要分布式锁的场景

操作类型

单个SQL写操作(UPDATE/DELETE)

多步骤业务逻辑(查询→判断→写)

原子性要求

仅需保证单次写操作的原子性

需保证整个业务链的原子性

服务耦合度

服务间无逻辑依赖

服务间需严格协调执行顺序

幂等性

依赖数据库唯一约束

需主动拦截重复请求

总的来说:单个数据源用悲观锁足以,多个数据源(数据库)要用分布式锁

相关文章
|
4月前
|
消息中间件 存储 缓存
再次了解kafka
Kafka通过offset机制解决消息重复消费问题,支持手动提交偏移量及唯一ID去重。它保证分区内的消息顺序消费,结合集群、副本与重平衡实现高可用。高性能设计包括顺序读写、分区、页缓存、零拷贝等。数据清理依赖保留时间或大小策略,点对点和发布订阅模式则通过消费者组实现。
|
4月前
|
消息中间件 NoSQL Java
延时实现
本节介绍了多种关闭过期订单的实现方案,包括定时任务、JDK延迟队列、Redis过期监听、Redisson延迟队列、RocketMQ延迟消息及RabbitMQ死信队列。各自优缺点明显,适用于不同业务场景,如定时任务适合小数据量,RocketMQ适合高并发解耦场景,而Redisson则使用简单且高效。选择时需综合考虑系统复杂度、数据量及可靠性要求。
|
4月前
|
存储 缓存 Linux
CPU上下文切换的原理及其在系统调用和进程切换中的应用
本内容深入解析了CPU上下文切换的原理及其在系统调用和进程切换中的应用。详细说明了CPU寄存器、程序计数器在任务切换中的作用,以及系统调用与进程上下文切换的区别。同时探讨了上下文切换带来的性能开销,涉及TLB和虚拟内存管理机制,帮助理解操作系统如何高效调度进程。
|
4月前
|
Docker 容器
初始ollama
Ollama 按需加载模型,不持续运行,闲置时自动卸载,节省内存。模型响应请求时驻留内存,保留时间由 OLLAMA_KEEP_ALIVE 控制。类似 Docker 部署方式,但无单模型启停命令,默认时间内自动停止。可间接通过停止服务或配置多端口实现管理。
|
4月前
|
负载均衡 网络性能优化
了解EMQ
EMQ通过MQTT协议的QoS机制保障消息可靠传输,支持QoS 0、1、2三个等级,分别实现消息最多一次、至少一次和恰好一次传递。对于延迟消息,EMQ X支持通过特殊主题前缀`$delayed/{DelayInterval}`实现延迟发布。点对点通信可通过不带群组的共享订阅(如`$queue/t/1`)实现,结合负载均衡策略如随机、轮询等,确保消息仅由一个订阅者接收;发布订阅模式则通过带群组的共享订阅(如`$share/组名称/t/1`)实现,确保每组一个订阅者收取消息。
|
4月前
|
存储 算法 Sentinel
熔断降级
本内容介绍了微服务中熔断降级的实现原理及Sentinel的底层机制。通过OpenFeign集成Sentinel,利用断路器统计异常和慢请求比例,触发熔断并降级,提升系统稳定性。还讲解了Sentinel使用的限流算法,如滑动窗口、令牌桶和漏桶算法,以应对不同场景下的流量控制需求。
|
4月前
|
SQL JavaScript Java
三层架构理解(实现前后端分离)
本文介绍了三层架构实现前后端分离的流程,从前端Vue发起请求,到后端Spring处理数据,最后返回结果并由前端渲染展示。同时详细解析了Bean重复问题的解决方案,包括使用@Service、@Primary、@Qualifier和@Resource注解进行依赖注入控制。此外还介绍了MyBatis中#{}与${}的区别及使用场景,以及三层架构中各组件的协作方式。
|
4月前
|
SQL Java 数据库连接
事务的七种传播行为及其应用场景
本文介绍了事务的七种传播行为及其应用场景,包括 PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、PROPAGATION_REQUIRES_NEW 等,帮助开发者理解事务管理机制。同时讲解了 Java 中 SQL 操作与对象数据不同步的问题,强调重新查询与手动管理的必要性,并说明 MyBatis 批量操作的最佳实践。
|
4月前
|
XML JSON Java
Spring框架中常见注解的使用规则与最佳实践
本文介绍了Spring框架中常见注解的使用规则与最佳实践,重点对比了URL参数与表单参数的区别,并详细说明了@RequestParam、@PathVariable、@RequestBody等注解的应用场景。同时通过表格和案例分析,帮助开发者正确选择参数绑定方式,避免常见误区,提升代码的可读性与安全性。