Redisson学习专栏(二):核心功能深入学习(分布式锁,分布式集合,原子操作与计数器,事件与监听)

article/2025/7/28 0:38:42

本文是“Redisson学习专栏”第二篇,聚焦其核心分布式功能实现原理与最佳实践

文章目录

  • 前言:分布式系统核心能力实践
  • 一、分布式锁:高并发下的守卫者
    • 1.1 可重入锁 (Reentrant Lock)
    • 1.2 公平锁 (Fair Lock)
    • 1.3 联锁 (MultiLock)
    • 1.4 红锁 (RedLock)
    • 关键参数说明
  • 二、Watchdog 机制与超时释放
    • 2.1 Watchdog (看门狗) 机制
      • 2.1.1看门狗机制为何选择10秒续期间隔?
    • 2.2 超时释放
  • 三、混合缓存利器:RMapCache
  • 四、协调任务流:分布式队列与发布订阅
    • 4.1 分布式队列
    • 4.2 发布订阅 (Pub/Sub):
  • 五、全局计数:分布式原子操作
  • 六、感知数据变化:监听 Redis 键空间事件
  • 总结


前言:分布式系统核心能力实践

在分布式架构中,跨进程的协调与数据一致性是关键技术挑战。作为基于Redis的Java客户端,Redisson通过原生分布式数据结构,为开发者提供了高效的分布式解决方案。
在上篇专栏完成基础架构解析后,本文将深入核心分布式功能实现:

  1. 分布式锁体系: 可重入锁、公平锁的Redis实现,以及MultiLock、RedLock的适用场景分析
  2. 缓存优化实践: RMapCache本地+分布式缓存混合模式
  3. 协调机制: 分布式队列与发布订阅的应用实现
  4. 原子操作: 分布式计数器的底层原理
  5. 事件驱动: 键空间监听机制与可靠性解析

技术栈要求:熟悉Redis基础及Java并发编程,示例基于Redisson 3.17+


一、分布式锁:高并发下的守卫者

1.1 可重入锁 (Reentrant Lock)

  • 原理: 基于 Redis Hash 结构存储锁信息。Key 为锁名称,Field 为客户端 ID(通常为 UUID + 线程 ID),Value 为持有计数(重入次数)。
  • 加锁: HINCRBY lock_name client_id 1(首次获取时设置过期时间)。
  • 解锁: HINCRBY lock_name client_id -1,当计数为 0 时删除 Key。通过 Lua 脚本保证原子性。
  • 核心价值: 同一线程可多次获取锁,避免死锁。
  • 适用场景: 标准分布式锁需求,支持同一线程重复加锁。
// 获取锁实例
RLock lock = redissonClient.getLock("orderLock");try {// 尝试加锁(默认启用Watchdog自动续期)lock.lock();// 支持重入lock.lock();// 执行业务逻辑processOrder();} finally {// 释放锁(需与加锁次数匹配)lock.unlock();lock.unlock();
}

1.2 公平锁 (Fair Lock)

  • 原理: 在可重入锁基础上增加排队机制。使用 Redis List 结构维护等待队列。
  • 加锁: 客户端尝试获取锁失败时,在队列尾部(RPUSH)添加自己的 ID,并订阅其前一个节点的释放消息(Pub/Sub),进入阻塞等待。
  • 解锁: 释放锁时,通过 Pub/Sub 通知队列中的下一个等待者。保证先到先得。
  • 适用场景: 需严格按申请顺序获取锁的场景。
RLock fairLock = redissonClient.getFairLock("taskQueueLock");try {// 加锁(默认30秒租期,Watchdog自动续期)fairLock.lock();// 获取队列首任务String task = taskQueue.poll();executeTask(task);} finally {fairLock.unlock();
}// 指定锁超时时间(不启用Watchdog)
fairLock.lock(10, TimeUnit.SECONDS);  // 10秒后自动释放

1.3 联锁 (MultiLock)

  • 原理: 将多个独立的锁(可属于不同的 Redis 节点)组合成一个逻辑锁。
  • 加锁: 按顺序尝试获取所有底层锁。若任意一个失败,则释放所有已获得的锁。
  • 解锁:按顺序释放所有底层锁。
  • 适用场景: 需同时锁定多个独立资源时(如:跨多个系统的操作)。
// 创建多个锁实例
RLock lock1 = redissonClient.getLock("resource1");
RLock lock2 = redissonClient.getLock("resource2");
RLock lock3 = redissonClient.getLock("resource3");// 构建联锁
RLock multiLock = redissonClient.getMultiLock(lock1, lock2, lock3);try {// 尝试获取所有锁(整体作为原子操作)boolean success = multiLock.tryLock(100, 10, TimeUnit.SECONDS);if (success) {// 所有资源锁定成功updateMultipleResources();}
} finally {multiLock.unlock();
}

1.4 红锁 (RedLock)

  • 目标: 在 Redis 主从架构下提供更强的一致性保证(防止主节点宕机未同步锁信息)。
  • 原理 (N 个独立 Master 节点):
    • 客户端获取当前时间 T1。
    • 依次向 N 个节点发送加锁命令(包含相同的随机值和锁过期时间)。
    • 计算获取锁耗时:锁有效时间 = 锁过期时间 - (T2 - T1)(T2 为最后响应时间)。
    • 当且仅当客户端在多数节点 (N/2 + 1) 上成功获取锁,且总耗时小于锁过期时间时,认为加锁成功。
  • 争议与注意事项:
    - 时钟漂移问题: 节点间时钟不一致可能影响锁有效性判断。
    - 性能与成本: 需要部署多个独立 Redis Master 节点,操作延迟较高。
    - Martin Kleppmann 的质疑: 详细讨论了网络分区、GC 暂停等场景下的潜在问题。
    - 实践建议: 仅在极高一致性要求且能容忍复杂性和性能损耗的场景下使用。需充分理解其局限性。Redisson 实现了完善的 RedLock 算法。
// 为每个独立Redis实例创建锁
Config config1 = new Config();
config1.useSingleServer().setAddress("redis://node1:6379");
RedissonClient client1 = Redisson.create(config1);
RLock lock1 = client1.getLock("criticalLock");Config config2 = // ... node2配置
RLock lock2 = // ... Config config3 = // ... node3配置
RLock lock3 = // ...// 构建红锁
RLock redLock = redissonClient.getRedLock(lock1, lock2, lock3);try {// 尝试加锁(超过半数节点成功即视为成功)if (redLock.tryLock()) {// 执行关键操作(如金融交易)executeCriticalOperation();}
} finally {redLock.unlock();
}// 关闭独立客户端(重要!)
client1.shutdown();
// ... 关闭其他客户端

关键参数说明

方法参数说明默认值
lock()阻塞直到获取锁,启用Watchdog-
lock(leaseTime, unit)指定锁持有时间,不启用Watchdog-
tryLock()立即返回获取结果(成功/失败)false
tryLock(waitTime, leaseTime, unit)等待指定时间,获取后持有指定时长waitTime=0

重要提示:

  1. 红锁需要至少3个独立Redis主节点(非集群分片)
  2. 调用unlock()次数需与lock()次数匹配
  3. 使用tryLock时务必检查返回值
  4. 红锁客户端需单独创建和关闭

二、Watchdog 机制与超时释放

2.1 Watchdog (看门狗) 机制

看门狗机制解决了这样的一个问题:业务执行时间可能超过锁的初始过期时间。
看门狗时序图

原理:

  • 客户端成功获取锁(未显式指定 leaseTime)时,Redisson 会启动一个后台守护线程。
  • 该线程定期(默认在锁过期时间的 1/3 时间点,如 30s 过期则每 10s)向 Redis 发送命令重置锁的过期时间(续期)。
  • 只要客户端 JVM 进程存活且持有锁,看门狗会持续续期。
  • 客户端主动释放锁或进程崩溃时,续期停止。

关键点: lock.lock() 默认启用 Watchdog(默认 30s 过期,每 10s 续期)。lock.lock(10, TimeUnit.SECONDS) 指定 leaseTime 则不启用 Watchdog。

2.1.1看门狗机制为何选择10秒续期间隔?

设计原理分析:
Redisson的看门狗机制选择10秒作为默认续期间隔,是经过多重技术考量后的平衡设计,核心因素如下:

  1. 过期时间的三分之一原则:首先默认过期时间为30秒,该比例确保在锁过期前至少进行3次续期尝试(0s, 10s, 20s)。
    网络容错设计
  2. 性能与可靠性的平衡点:
续期间隔优点缺点
5秒容错性更高Redis压力倍增
15秒减少Redis负载容错窗口不足
10秒最佳平衡-

关键设计:

  • 时钟漂移容错: 假设各节点时钟存在1-2秒误差,10秒间隔确保时钟漂移不会导致续期失败。计算公式:续期间隔 > 最大时钟漂移 × 3
  • GC暂停容忍: 考虑JVM的Stop-The-World GC暂停(通常<1秒),10秒间隔可承受多次GC暂停影响。
  • 网络延迟补偿:
// Redisson续期操作核心逻辑
void scheduleExpirationRenewal() {// 计算下次续期时间 = 当前时间 + 1/3锁有效期Timeout task = timer.newTimeout(new TimerTask() {public void run(Timeout timeout) {// 异步续期操作(含网络请求)renewExpirationAsync(); }}, lockWatchdogTimeout / 3, TimeUnit.MILLISECONDS);
}
  • 故障转移窗口:Redis集群故障转移时间通常5-10秒,10秒间隔为集群切换留出缓冲时间。

关键结论:10秒间隔是分布式系统设计中的经典时间窗口,平衡了网络不确定性(Network Uncertainty)和系统负载。它确保即使连续2次续期失败(20秒),锁仍有10秒的有效期缓冲,为故障排查留出黄金时间。

2.2 超时释放

  • 如果使用了 lock.lock(leaseTime, unit) 指定租约时间,Redis 会在 leaseTime 后自动删除 Key 释放锁。
  • 风险: 业务执行时间超过 leaseTime 会导致锁提前释放,其他客户端可能获取锁操作共享资源,造成数据不一致。谨慎使用,需确保业务最大执行时间远小于 leaseTime。

三、混合缓存利器:RMapCache

RMapCache 在分布式 Map (RMap) 基础上增加了本地缓存 (Local Cache) 和条目过期淘汰功能。
原理:

  1. 本地缓存: 客户端在内存中维护一份热点数据的副本。
  2. 数据同步: 通过 Redis 的 Pub/Sub 通道监听 Map 的更新/删除事件。当其他节点修改了 Map 中的数据,本地缓存会收到通知并失效对应的条目。
  3. 本地缓存淘汰策略: 支持 LRU (最近最少使用)、LFU (最不经常使用)、SOFT (软引用)、WEAK (弱引用) 等策略限制本地内存占用。
  4. Redis 缓存过期: 支持为 Map 中的单个条目设置 TTL (生存时间) 或 Max Idle Time (最大空闲时间)。

优势:

  • 显著降低延迟: 读取本地缓存速度极快。
  • 减轻 Redis 压力: 大量读请求被本地缓存吸收。
  • 保留分布式特性: 写操作和缓存失效通知保证不同节点间数据的最终一致性。

使用示例与配置:

RMapCache<String, SomeObject> mapCache = redisson.getMapCache("myMapCache");
// 配置本地缓存:最大容量500,淘汰策略LFU,10分钟后未访问则失效
LocalCachedMapOptions<String, SomeObject> options = LocalCachedMapOptions.<String, SomeObject>defaults().cacheSize(500).evictionPolicy(EvictionPolicy.LFU).timeToLive(10, TimeUnit.MINUTES);
RMapCache<String, SomeObject> mapCacheWithLocalCache = redisson.getMapCache("myMapCache", options);// 写入 (会广播失效其他节点的本地缓存)
mapCacheWithLocalCache.put("key1", new SomeObject(), 5, TimeUnit.MINUTES); // 设置该条目在Redis中5分钟后过期// 读取 (优先读本地缓存,不存在则从Redis加载并缓存)
SomeObject obj = mapCacheWithLocalCache.get("key1");

注意事项: 本地缓存带来性能提升的同时,也引入了弱一致性。在极端网络分区情况下,不同节点的本地缓存可能短暂不一致。适用于对一致性要求不苛刻的高频读场景。

四、协调任务流:分布式队列与发布订阅

4.1 分布式队列

  • RQueue: 基于 Redis List (LPUSH/RPOP, RPUSH/LPOP) 实现的普通 FIFO 队列。
  • RBlockingQueue: RQueue 的阻塞版本。核心方法是阻塞式的 take() 和 poll(timeout)。
    • take() 原理: 客户端使用 BLPOP/BRPOP 命令阻塞等待队列中出现元素。Redis 会在元素入队时唤醒等待的客户端。
    • 应用场景: 简单的任务队列、解耦生产者消费者。
RBlockingQueue<String> queue = redisson.getBlockingQueue("myTaskQueue");
// 生产者
queue.offer("task1");
// 消费者 (阻塞等待)
String task = queue.take();
process(task);

4.2 发布订阅 (Pub/Sub):

  • RTopic: 实现基于 Redis Pub/Sub 机制的消息发布/订阅模型。
  • 原理: 发布者 (publish) 向指定频道发送消息。所有订阅了该频道的客户端都会收到消息。
  • 集群支持: Redisson 的 RTopic 能自动处理 Redis 集群环境下的消息路由。
  • 应用场景: 广播通知、事件驱动架构、实时数据推送。
RTopic topic = redisson.getTopic("myTopic");
// 订阅者 (监听消息)
int listenerId = topic.addListener(MessageType.class, (channel, msg) -> {System.out.println("Received: " + msg);
});
// 发布者
topic.publish(new MessageType("Hello Redisson Pub/Sub!"));
// 取消订阅
topic.removeListener(listenerId);

五、全局计数:分布式原子操作

  • RAtomicLong / RAtomicDouble:
    • 原理: 基于 Redis 的原子命令 INCRBY, DECRBY, INCRBYFLOAT 等实现。这些命令在 Redis 单线程模型下天然具有原子性。
    • 核心方法:
      • get(), set(newValue)
      • incrementAndGet(), decrementAndGet()
      • addAndGet(delta), getAndAdd(delta)
      • (RAtomicDouble特有) addAndGet(deltaDouble), getAndAdd(deltaDouble)
    • 应用场景: 全局唯一 ID 生成器(如 INCR)、库存计数、投票计数、秒杀活动计数、分布式指标统计。
RAtomicLong counter = redisson.getAtomicLong("globalCounter");
long currentId = counter.incrementAndGet(); // 原子递增并获取新值

六、感知数据变化:监听 Redis 键空间事件

Redisson 允许监听 Redis 的键空间通知 ,如键的过期、删除、更新等。

  1. 配置 Redis:需在 redis.conf 中启用键空间通知(生产环境应谨慎选择需要的事件类型):
notify-keyspace-events Exgx  # K:键空间事件,E:键事件事件,x:过期事件,g:一般事件(如 del),e:驱逐事件(maxmemory)
  1. Redisson 监听器:
RPatternTopic keyEventTopic = redisson.getPatternTopic("__keyevent@*");
// 监听所有键事件
int listenerId = keyEventTopic.addListener(PatternStatusListener, new PatternMessageListener<String>() {@Overridepublic void onMessage(CharSequence pattern, CharSequence channel, String message) {// pattern: "__keyevent@*", channel: e.g. "__keyevent@0__:expired", message: the key nameSystem.out.println("Event: " + channel + ", Key: " + message);if (channel.toString().endsWith(":expired")) {handleKeyExpiration(message);} else if (channel.toString().endsWith(":del")) {handleKeyDeletion(message);}}
});
  • 常用事件通道:keyevent@:expired (过期), keyevent@:del (删除), keyevent@:set (设置) 等。
  • keyspace@: 通道监听特定键的事件(需额外配置)。

应用场景:

  • 缓存失效监听: 监听 expired 事件,触发缓存重建逻辑。
  • 数据变更通知: 监听特定键的 set/del 事件,执行关联操作(如更新索引、清理关联资源)。
  • 分布式锁超时监控: 监听锁 Key 的 expired 事件,感知锁异常释放(需结合业务逻辑谨慎处理)。

注意事项:

  • 可靠性: 键空间通知是 Fire-and-Forget 的,不保证可靠传递(网络问题、客户端断开时可能丢失通知)。
  • 性能影响: 大量事件通知会对 Redis 和网络造成额外开销。
  • 事件延迟: 过期事件存在一定延迟(Redis 定期检查 + 事件传递时间)。

总结

通过本文的深度探索,我们揭示了 Redisson 如何将 Redis 从单纯的数据存储转变为分布式系统的神经中枢。这些核心功能不仅是技术组件的堆砌,更是解决分布式系统痛点的范式升级:

  • 分布式锁体系 超越了简单的互斥控制,通过 Watchdog 机制和红锁算法,在可用性和一致性之间建立了动态平衡
  • RMapCache 混合缓存 打破了本地与分布式缓存的对立,用分层设计实现亚毫秒级响应与TB级容量的统一
  • 原子操作与队列 将并发编程模型扩展到分布式维度,使跨服务的状态同步如同单机编程般自然
  • 键空间监听 开启了真正的数据驱动架构,让业务逻辑能实时响应全局状态变化

技术选型黄金法则

场景推荐组件避坑指南
高频短期锁可重入锁+Watchdog避免设置过短leaseTime
跨资源事务MultiLock严格按顺序获取锁
超高一致性要求RedLock部署3+独立节点,监控时钟同步
读密集型热点数据RMapCache+LFU策略控制本地缓存大小防OOM
实时事件响应键空间监听+本地缓存配置notify-keyspace-events参数

警示:没有完美的分布式解决方案。红锁的时钟争议提醒我们:任何分布式协调都需在CAP三角中取舍。Redisson的价值在于,它让这种取舍变得可量化、可配置、可观测

学习建议:

# 立即验证本文知识
git clone https://github.com/redisson/redisson-examples

讨论题:在您当前的项目中,Redisson 的哪个功能能带来最大价值?您遇到过哪些分布式协调的"诡异"问题?

下期预告:Redission高级特性与实战(Spring/Spring Boot 集成,响应式编程,分布式服务,性能优化)


http://www.hkcw.cn/article/dbeGFuxKaN.shtml

相关文章

学习路之PHP--easyswoole_panel安装使用

学习路之PHP--easyswoole_panel安装使用 一、新建文件夹二、安装三、改配置地址四、访问 IP:Port 自动进入index.html页面 一、新建文件夹 /www/wwwroot/easyswoole_panel 及配置ftp 解压easyswoole_panel源码 https://github.com/easyswoole-panel/easyswoole_panel 二、安…

基于分布式状态机的集装箱智能道口软件架构方法

集装箱码头对进出场道口的通过能力始终是要求最高的&#xff0c;衡量道口的直接指标为道口通行效率&#xff0c;道口通行效率直接体现了集装箱码头的作业效率以及对外服务水平&#xff0c;进而直接影响到码头的综合能力。所以&#xff0c;码头普遍使用智能道口实现24小时无人值…

2014药柜设计问题

1 题目描述 D题 储药柜的设计 储药柜的结构类似于书橱&#xff0c;通常由若干个横向隔板和竖向隔板将储药柜分割成若干个储药槽(如图1所示)。为保证药品分拣的准确率&#xff0c;防止发药错误&#xff0c;一个储药槽内只能摆放同一种药品。药品在储药槽中的排列方式如图2所示。…

c# 获取电脑 分辨率 及 DPI 设置

using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices;/// <summary> /// 这个可以 /// </summary> class Program {static void Main(){//设置DPI感知try{SetProcessDpiAwareness(…

2025年渗透测试面试题总结-匿名[校招]红队攻防工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 匿名[校招]红队攻防工程师 1. 00截断的原理 2. Java回显通用思路及JDK差异 3. Redis利用姿势及环境差异 …

高级数据结构与算法期末考试速成记录

高级数据结构与算法期末考试速成记录 0.分治中的一些知识点 Master公式&#xff08;又称主定理&#xff0c;Master Theorem&#xff09;是一种用于快速求解分治递归算法时间复杂度 的数学工具&#xff0c;适用于递归式形如以下形式的算法&#xff1a; T ( n ) a T ( n b ) …

Telerik生态整合:Kendo UI for Angular组件在WinForms应用中的深度嵌入(一)

Telerik DevCraft包含一个完整的产品栈来构建您下一个Web、移动和桌面应用程序。它使用HTML和每个.NET平台的UI库&#xff0c;加快开发速度。Telerik DevCraft提供完整的工具箱&#xff0c;用于构建现代和面向未来的业务应用程序&#xff0c;目前提供UI for ASP.NET MVC、Kendo…

深入浅出程序设计竞赛(洛谷基础篇) 第十四章 搜索

文章目录 前言例14-1 四阶数独前置知识&#xff1a; 例14-2八皇后例14-3 kkksc03考前临时抱佛脚例14-4 马的遍历前置知识 例14-5 奇怪的电梯例14-6 Meteor Shower S习题14-1.1 选数例14-1 四阶数独前置知识&#xff1a; 例14-2八皇后例14-3 kkksc03考前临时抱佛脚例14-4 马的遍…

图书管理系统的设计与实现

湖南软件职业技术大学 本科毕业设计(论文) 设计(论文)题目 图书管理系统的设计与实现 学生姓名 学生学号 所在学院 专业班级 毕业设计(论文)真实性承诺及声明 学生对毕业设计(论文)真实性承诺 本人郑重声明:所提交的毕业设计(论文)作品是本人在指导教师的指导下,独…

【Java基础-环境搭建-创建项目】IntelliJ IDEA创建Java项目的详细步骤

在Java开发的世界里&#xff0c;选择一个强大的集成开发环境&#xff08;IDE&#xff09;是迈向高效编程的第一步。而IntelliJ IDEA无疑是Java开发者中最受欢迎的选择之一。它以其强大的功能、智能的代码辅助和简洁的用户界面&#xff0c;帮助无数开发者快速构建和部署Java项目…

医疗IT系统绝缘监测及故障定位,绝缘监测技术在医院关键区域的应用

医院作为重要的公共设施&#xff0c;其供配电系统的可靠性和安全性直接关系到患者的生命安全。为确保医院电力系统的稳定&#xff0c;GB/T 16895.24《建筑物电气装置》对医疗场所按用电的安全等级进行了细致的分类&#xff0c;并针对不同的类别推荐相应的电力系统配置。其中&am…

进程间通信及管道(理论)

目录 进程间通信介绍 进程间通信目的 进程间通信发展 进程间通信分类 管道 什么是管道 匿名管道 实例代码 用fork来共享管道原理 管道读写规则 管道特点 命名管道 创建一个命名管道 匿名管道与命名管道的区别 命名管道的打开规则 进程间通信介绍 进程间通信目的 数据传输&#…

如何安全地清洁 Windows10/11PC上的SSD驱动器

“我在 Windows 10 电脑上安装了新的 SSD&#xff0c;我要删除旧的 SSD 驱动器。但我不知道如何清洁电脑上的 SSD 驱动器。我想清除其中的所有内容。” 那么&#xff0c;您想知道如何在 Windows 10/11 PC 上清洁 SSD 驱动器吗&#xff1f;也许您只是想释放宝贵的空间并提高性能…

换ip是换网络的意思吗?怎么换ip地址

在数字化时代&#xff0c;IP地址作为我们在网络世界的"身份证"&#xff0c;其重要性不言而喻。许多人常将"换IP"与"换网络"混为一谈&#xff0c;实际上两者虽有联系却存在本质区别。本文将澄清这一概念误区&#xff0c;并详细介绍多种更换IP地址…

智能化能源管理系统在“双碳”背景下的新价值

安科瑞刘鸿鹏 摘要 2022年已并网的储能项目中,用户侧并网占比为8.36%,其中工商业储能规模为占比为98.6%。随着各省市的峰 谷价差拉大,部分省市可实现两充两放,工商业储能会更 加具有经济性,加上限电政策的影响,工商业储能将在 2023-2025年逐渐发展成主要的增长点&#xff…

带sdf 的post sim 小结

1.SDF文件主要内容 Delays&#xff08;module&#xff0c;device&#xff0c;interconnect&#xff0c;port&#xff09; Timing checks&#xff08;setup&#xff0c;hold&#xff0c;setuphold&#xff0c;recovery&#xff0c;removal&#xff0c;recrem&#xff09; Timing…

《JavaScript高级程序设计》读书笔记 34 - 代理基础

感谢点赞、关注和收藏! 上一篇类,这一篇进入书的第 9 章 - 代理与反射,首先是代理基础。 代理基础 代理是目标对象的抽象。从很多方面看,代理类似 C++指针,因为它可以用作目标对象的替身,但又完全独立于目标对象。目标对象既可以直接被操作,也可以通过代理来操…

《计算机仿真》——引领计算机仿真领域的学术前沿

期刊名称&#xff1a;计算机仿真 (Computer Simulation) 主办单位&#xff1a;中国航天科工集团公司第十七研究所 出版周期&#xff1a;月刊 出版地&#xff1a;北京市 语种&#xff1a;中文 开本&#xff1a;大16开 ISSN&#xff1a;1006-9348 CN&#xff1a;11-3724/TP 邮发代…

java-文件IO

文件IO 操作系统有一个专门的模块-文件系统&#xff0c;来管理文件。并提供了 api 供我们使用。 文件系统 使用 N叉树 来组织文件。 操作系统使用 “路径” 来描述文件的位置。路径的表示又分为 绝对路径 和 相对路径 绝对路径 &#xff1a;从树的的根节点&#xff08;Wind…

数据基座觉醒!大数据+AI如何重构企业智能决策金字塔(上)

1. 数据金字塔的千年进化史 1.1 从地窖到云端的存储革命 某家电企业在2010年遭遇库存危机时&#xff0c;市场部门需要三天才能从纸质单据中统计出全国滞销型号。当他们的数据工程师在2023年轻声唤醒对话式分析机器人&#xff0c;同样的需求响应时间缩短至9秒。 数据分层架构的…