【java】 分布式锁实现和选型

文章目录

      • 引言:分布式锁的重要性与分布式系统中的常见问题和需求
        • 分布式锁的重要性
        • 分布式系统中常见的问题和需求
        • 分布式锁与本地锁的区别
      • 基于数据库的分布式锁
        • 基于数据库实现分布式锁
        • 实现原理
        • Java代码示例
        • 优点和缺点分析
      • 基于Redis的分布式锁
        • 实现原理
        • Java代码示例使用 `Redisson`
        • 优点和缺点分析
      • 基于Zookeeper的分布式锁
        • 实现原理
        • Java代码示例使用 `Curator`
        • 优点和缺点分析
      • 分布式锁的选型指南
        • 各种实现方式的适用场景
        • 性能和安全性比较
        • 实际应用中的考虑因素
      • 常见面试题
        • 1. 什么是分布式锁?为什么在分布式系统中需要分布式锁?
        • 2. 描述一下基于 Redis 的分布式锁的实现方式及其优缺点。
        • 3. Zookeeper 和 Redis 在分布式锁实现上有什么不同?
        • 4. 如何解决分布式锁的死锁问题?
        • 5. 在分布式锁的实现中,如何保证锁的公平性?
        • 6. 死锁问题及预防
        • 7. 锁的公平性问题
        • 8. 高可用性和容错性

引言:分布式锁的重要性与分布式系统中的常见问题和需求

分布式锁的重要性

在分布式系统中,多个进程或服务可能需要同时访问和操作共享资源,如数据库、文件系统等。如果这些操作不受控制,就可能导致数据不一致或操作冲突。分布式锁是解决这一问题的关键技术,它能确保在同一时刻,只有一个进程或服务可以执行特定的操作。

例如,考虑一个在线商店的库存管理系统,如果多个用户同时尝试购买最后一个库存项,未经同步的操作可能导致超卖现象。使用分布式锁可以确保每次只有一个操作能够修改库存数量,从而维护数据的准确性和一致性。

分布式系统中常见的问题和需求
  1. 数据一致性

    • 在没有适当同步机制的情况下,多个节点更新同一数据可能导致不一致状态。分布式锁提供了一种机制,确保在任何时刻只有一个节点能够操作数据。
  2. 系统性能

    • 分布式锁的实现需要在性能和延迟之间做出权衡。锁的实现不应该成为系统性能的瓶颈。
  3. 容错性和高可用性

    • 在分布式环境中,节点可能会失败。一个健壮的分布式锁系统应该能够处理节点故障,不会因为单个节点的问题而导致整个系统的锁服务不可用。
  4. 锁的管理和监控

    • 在复杂的分布式系统中,锁的管理应简单且自动化,同时需要提供监控机制来分析锁的使用情况和性能瓶颈。
  5. 死锁预防和解决

    • 死锁是分布式系统中常见的问题,需要有策略来检测和解决死锁,以保持系统的流畅运行。

通过解决这些问题,分布式锁帮助构建一个稳定、可靠且高效的分布式系统。在接下来的章节中,我们将探讨不同的分布式锁实现方式,以及如何选择适合特定应用场景的锁系统。

分布式锁与本地锁的区别
  1. 作用范围

    • 本地锁:通常用于单一进程内或单机多线程环境中,用来控制同一进程内的不同线程对共享资源的访问。
    • 分布式锁:用于控制多个分布在不同服务器或容器上的进程对共享资源的访问。
  2. 实现方式

    • 本地锁:实现相对简单,如Java中的synchronizedReentrantLock等,这些锁依赖于操作系统的支持,只在单一JVM内有效。
    • 分布式锁:需要通过网络协调不同节点之间的锁状态,常见的实现方式包括使用外部存储或服务,如Redis、Zookeeper或数据库来存储锁的状态。
  3. 性能和复杂性

    • 本地锁:性能通常较高,因为它们不涉及网络通信,并且锁的管理完全在本地进行。
    • 分布式锁:可能会因网络延迟和锁的管理(如获取、续租、释放锁等操作)复杂性增加而影响性能。
  4. 可靠性和容错性

    • 本地锁:容错性较低,如果持有锁的线程或进程失败,可能会导致锁无法释放。
    • 分布式锁:设计时通常会考虑高可用和容错性,例如,使用心跳、锁续租等机制来处理持有锁的节点故障问题。

基于数据库的分布式锁

基于数据库实现分布式锁

数据库实现分布式锁通常依赖于数据库的原子操作,如行锁或者使用特定的SQL语句来保证同步。

实现方式

  • 利用唯一索引:可以通过尝试插入一个具有唯一索引的键值对来实现锁。如果插入成功,则获取锁;如果因为唯一性约束失败,则获取锁失败。
  • 使用行锁:通过对数据库中的特定行进行加锁操作,如使用SELECT FOR UPDATE语句,来阻止其他事务修改这一行数据。

示例代码(使用MySQL):

-- 尝试获取锁
INSERT INTO locks (lock_key, lock_status) VALUES ('inventory_lock', 'locked') ON DUPLICATE KEY UPDATE lock_status = 'locked';-- 释放锁
UPDATE locks SET lock_status = 'unlocked' WHERE lock_key = 'inventory_lock';
实现原理

基于数据库的分布式锁通常涉及使用数据库表作为锁的记录。锁的获取是通过插入或更新表中的特定记录来实现的。如果操作成功(例如,插入一行数据),则认为锁被成功获取;如果操作失败(例如,因为违反唯一性约束),则认为锁获取失败。

Java代码示例

以下是一个简单的基于数据库的分布式锁实现示例,使用JDBC进行数据库操作:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class DatabaseLock {private Connection connection;public DatabaseLock(Connection connection) {this.connection = connection;}public boolean tryLock(String lockId) {String sql = "INSERT INTO locks(lock_id, locked) VALUES (?, 1) ON DUPLICATE KEY UPDATE locked = 1;";try (PreparedStatement statement = connection.prepareStatement(sql)) {statement.setString(1, lockId);int result = statement.executeUpdate();return result == 1;} catch (SQLException e) {return false;}}public void unlock(String lockId) {String sql = "DELETE FROM locks WHERE lock_id = ?;";try (PreparedStatement statement = connection.prepareStatement(sql)) {statement.setString(1, lockId);statement.executeUpdate();} catch (SQLException e) {e.printStackTrace();}}
}

在这个例子中,我们假设有一个名为 locks 的表,其中包含 lock_id 字段。tryLock 方法尝试插入一行数据,如果 lock_id 已存在,则更新该记录。如果插入或更新成功,锁被认为是获取成功的。

优点和缺点分析

优点

  1. 简单易实现:大多数应用已经使用数据库,因此不需要额外的系统或技术栈。
  2. 易于理解:这种方法不需要复杂的外部依赖或额外学习成本。

缺点

  1. 性能问题:数据库锁可能会对数据库性能产生显著影响,特别是在高并发场景下。
  2. 不是专门为锁设计:数据库没有为处理锁的操作进行优化,可能不如其他方法(如Redis或Zookeeper)高效。
  3. 可靠性问题:在数据库宕机或网络问题的情况下,锁的状态可能变得不确定。

基于数据库的分布式锁适用于请求量不太高且已经存在数据库依赖的场景。在高并发或对延迟敏感的系统中,可能需要考虑其他更专业的分布式锁实现方式。

基于Redis的分布式锁

Redis是一种支持多种数据结构的内存数据存储系统,由于其高性能和原子操作特性,非常适合实现分布式锁。

实现方式

  • SET命令:可以使用Redis的SET命令与参数NX(只在键不存在时设置键)和EX(设置键的过期时间)来实现锁的功能。

示例代码(使用Redis命令):

# 尝试获取锁
SET lock_key "your_value" NX EX 30
# 如果返回 OK,则锁设置成功,否则设置失败。# 释放锁
DEL lock_key
实现原理

Redis 是一个高性能的键值存储系统,它的操作具有原子性,因此常被用来实现分布式锁。基于 Redis 的分布式锁通常使用其 SET 命令的 NX(Not Exists)和 EX(Expire)选项来实现。这种方法确保了锁的设置(如果键不存在)和超时时间的设置是原子性操作。

  • SETNX 命令(已被 SET key value NX EX max-lock-time 替代)用于尝试设置一个键,如果该键不存在,则操作成功(锁被获取),否则操作失败(锁已被其他客户端持有)。
  • EXPIRE 设置键的过期时间,确保即使锁的持有者因为某些原因未能释放锁,锁也会在一定时间后自动释放,防止死锁。
Java代码示例使用 Redisson

Redisson 是一个在 Redis 的基础上实现的 Java 分布式和可扩展的 Java 数据结构。以下是一个使用 Redisson 实现的 Redis 分布式锁的示例。

首先,需要在项目中添加 Redisson 依赖:

<!-- Maven dependency -->
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.4</version>
</dependency>

然后,可以使用以下代码来获取和释放一个分布式锁:

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;public class RedisLockExample {public static void main(String[] args) {Config config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379");RedissonClient redisson = Redisson.create(config);RLock lock = redisson.getLock("anyLock");try {// 尝试获取锁,最多等待100秒,锁定后10秒自动解锁if (lock.tryLock(100, 10, TimeUnit.SECONDS)) {try {// 业务逻辑System.out.println("Lock acquired");} finally {lock.unlock();System.out.println("Lock released");}}} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {redisson.shutdown();}}
}
优点和缺点分析

优点

  1. 性能高:Redis 基于内存操作,响应速度快,适用于高并发场景。
  2. 轻量级:相比基于数据库的锁,Redis 的实现更为轻量,不需要复杂的表结构和查询。
  3. 自动解锁:通过设置键的过期时间,可以防止死锁的发生。

缺点
4. 单点故障问题:如果使用单个 Redis 节点,可能会因为节点故障而导致锁服务不可用。虽然可以通过 Redis 集群来提高可用性,但实现和管理相对复杂。
5. 时钟依赖:Redis 锁的实现依赖于时间,如果系统中的服务器时钟不同步,可能会导致锁的提前释放或过期。
6. 不保证锁的公平性:Redisson 提供的锁不保证请求锁的公平性,可能会导致某些客户端饥饿。

基于Zookeeper的分布式锁

Zookeeper是一个为分布式应用提供协调服务的软件,它提供了一种树形的目录结构,非常适合用来构建分布式锁。

实现方式

  • 创建临时顺序节点:客户端为锁创建一个临时顺序节点,然后检查是否为最小节点。如果是,表示获取了锁;如果不是,监听比自己小的最近的一个节点的删除事件,等待获取锁。

示例代码(使用Zookeeper的伪代码):

// 尝试获取锁
String myNode = zk.create("/locks/my_lock_", null, ACL, CreateMode.EPHEMERAL_SEQUENTIAL);
List<String> nodes = zk.getChildren("/locks", false);
Collections.sort(nodes);
if (myNode.equals("/locks/" + nodes.get(0))) {// 获取锁成功
} else {// 等待锁释放
}// 释放锁
zk.delete(myNode, -1);
实现原理

Zookeeper 是一个开源的分布式协调服务,它提供了一种用于管理大量主机的高可用性的分层服务。Zookeeper 的数据模型类似于文件系统,包含节点(Znodes),这些节点可以是持久的或临时的(临时节点在创建它们的客户端会话结束时自动删除)。基于 Zookeeper 的分布式锁主要利用了这些临时顺序节点。

为了获取锁,客户端在锁的根节点下创建一个临时顺序节点。客户端获取所有子节点的列表,检查自己创建的节点是否为序号最小的节点。如果是,该客户端持有锁;如果不是,它就监听序号比自己小的最近的一个节点的删除事件,这个监听实现了客户端的等待机制。

Java代码示例使用 Curator

首先,需要添加 Curator 的依赖到你的项目中:

<dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>5.1.0</version>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>5.1.0</version>
</dependency>

下面是使用 Curator 实现的分布式锁的一个简单示例:

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;public class ZookeeperLock {private CuratorFramework client;public void startClient() {client = CuratorFrameworkFactory.newClient("localhost:2181", // Zookeeper 服务器地址new ExponentialBackoffRetry(1000, 3) // 重试策略);client.start();}public void lockAndRun() throws Exception {InterProcessMutex lock = new InterProcessMutex(client, "/locks/my_lock");try {if (lock.acquire(10, TimeUnit.SECONDS)) {try {// 在这里执行任务System.out.println("Lock acquired, executing task");} finally {lock.release();}} else {System.out.println("Could not acquire the lock");}} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) throws Exception {ZookeeperLock example = new ZookeeperLock();example.startClient();example.lockAndRun();}
}
优点和缺点分析

优点

  1. 可靠性:Zookeeper 保证了锁的安全性和一致性,即使在网络分区情况下也能正常工作。
  2. 顺序保证:Zookeeper 的顺序节点保证了请求的有序处理。
  3. 死锁避免:临时节点确保锁会在持有者崩溃时自动释放,避免了死锁的问题。

缺点
4. 性能:与基于内存的系统(如 Redis)相比,Zookeeper 的性能较低,因为它需要维护更多的状态和通信。
5. 复杂性:Zookeeper 的设置和维护比较复杂,需要适当的配置和监控。
6. 资源消耗:Zookeeper 客户端需要持续和服务端保持连接,这可能会消耗更多的系统资源。

分布式锁的选型指南

在选择分布式锁的具体实现时,需要根据应用的需求、性能要求、安全性需求以及现有的技术栈来决定。以下是对不同实现方式的适用场景、性能和安全性的比较,以及在实际应用中需要考虑的因素。

各种实现方式的适用场景
  1. 基于数据库的分布式锁

    • 适用于已经使用关系数据库,且事务量不是特别高的场景。
    • 当分布式系统中的各个组件已经依赖于同一个数据库时,使用数据库锁可以避免引入额外的技术依赖。
  2. 基于Redis的分布式锁

    • 适用于需要快速响应和高吞吐量的场景。
    • 当系统需要高性能锁机制,且已经使用Redis作为缓存或其他中间件时,基于Redis的锁是一个好选择。
  3. 基于Zookeeper的分布式锁

    • 适用于对数据一致性要求极高的场景。
    • 在分布式系统中,如果需要确保数据的强一致性,Zookeeper提供的锁机制是非常合适的,尤其是在处理复杂的协调任务时。
性能和安全性比较
  • 性能

    • Redis 提供了最快的锁操作性能,适合高并发环境。
    • Zookeeper 在性能上逊色于Redis,但提供更强的一致性保证。
    • 数据库 通常性能最低,特别是在高并发场景下,但对于某些小规模或低并发应用可能足够使用。
  • 安全性

    • Zookeeper 提供强一致性保证,是三者中最安全的选择。
    • Redis 在大部分情况下足够安全,但在网络分区等极端情况下可能会出现锁失效的问题。
    • 数据库 依赖于数据库本身的事务和锁机制,通常安全性较高,但需要正确配置和使用。
实际应用中的考虑因素
  • 技术栈兼容性:选择与现有技术栈兼容的解决方案可以减少学习成本和技术风险。
  • 部署和维护成本:考虑到引入新技术可能带来的部署和维护工作量,选择操作简单、支持良好的解决方案。
  • 容错性和可靠性:系统的关键部分需要高可靠性的锁机制,选择能够提供强一致性和高可用性的解决方案。
  • 扩展性:随着系统规模的扩大,锁服务的扩展性变得至关重要。选择可以轻松扩展以支持更高并发和更大数据量的锁解决方案。

常见面试题

在面试中,关于分布式锁的问题可以帮助面试官评估应聘者对分布式系统、一致性和可用性等概念的理解。以下是一些常见的分布式锁相关面试题及其解析:

1. 什么是分布式锁?为什么在分布式系统中需要分布式锁?

回答概要:
分布式锁是用来在分布式系统中管理对共享资源或服务的访问,确保在同一时间内只有一个进程或线程能执行特定的操作。在分布式系统中,由于资源可能被多个节点同时访问,为了防止数据竞争和保证操作的原子性,需要使用分布式锁。

2. 描述一下基于 Redis 的分布式锁的实现方式及其优缺点。

回答概要:
基于 Redis 的分布式锁通常使用 SETNX 命令来设置一个锁,该命令只在键不存在时设置键,从而确保锁的唯一性。另外,可以使用 EXPIRE 命令给锁设置一个过期时间,防止锁永久占用。

优点:

  • 高性能和高可用性。
  • 简单易用,支持自动过期避免死锁。

缺点:

  • 在 Redis 集群模式下,锁不具有强一致性。
  • 需要处理好锁的续命问题,避免因为客户端崩溃导致的资源锁定。
3. Zookeeper 和 Redis 在分布式锁实现上有什么不同?

回答概要:
Zookeeper 通过创建临时顺序节点来实现分布式锁。客户端创建节点后,如果该节点是最小的节点,则获取锁;否则监听比自己小的最近的一个节点,直到它被删除。

不同点:

  • 一致性保证: Zookeeper 提供强一致性,而 Redis 提供的是最终一致性。
  • 实现复杂性: Zookeeper 的锁实现相对复杂,需要处理节点监听和排序;Redis 的实现则相对简单。
  • 性能: Redis 在性能上通常优于 Zookeeper,尤其是在高并发场景下。
4. 如何解决分布式锁的死锁问题?

回答概要:
死锁问题可以通过设置锁的超时时间来解决,确保即使锁的持有者因为崩溃或其他原因无法释放锁,锁也会因为超时而自动释放。此外,使用心跳机制续租锁可以防止因为网络问题导致的锁提前释放。

5. 在分布式锁的实现中,如何保证锁的公平性?

回答概要:
保证锁的公平性通常需要实现一个有序队列,使得请求锁的顺序与获取锁的顺序一致。在Zookeeper中,可以利用临时顺序节点自然排序的特性来实现公平性;而在Redis等其他系统中,可能需要额外的逻辑来管理队列。

这些问题和答案不仅涵盖了分布式锁的基础知识,还触及了实现细节和实际应用中的考虑,有助于准备相关的技术面试。

6. 死锁问题及预防

定义与原因:
死锁是指两个或多个操作系统的进程因争夺资源而造成的一种僵局,它们相互等待对方释放资源。在分布式锁的环境中,死锁可能发生在网络延迟、进程崩溃或锁没有正确释放的情况下。

预防措施:

  • 锁超时: 设定锁的最大持有时间,超时后锁自动释放。这可以通过设置锁的过期时间来实现,例如在 Redis 和 Zookeeper 中都可以设置。
  • 心跳机制: 如果锁支持续期(例如 Redis 的 RedLock 算法),客户端应定期发送心跳来续期锁,避免因客户端崩溃而未能释放锁。
  • 检测死锁: 在某些系统中,可以通过算法检测死锁的可能性,一旦检测到死锁的风险,系统可以主动中断某些操作,释放锁。
7. 锁的公平性问题

定义与原因:
锁的公平性是指请求锁的顺序与获取锁的顺序是否一致。在非公平锁中,新的请求可能会在等待队列中的请求之前获得锁,这可能导致某些请求长时间得不到处理。

解决方案:

  • 使用公平锁: 例如在 Java 的 ReentrantLock 类中,可以选择公平模式,确保按照请求的顺序获得锁。
  • Zookeeper 实现: Zookeeper 通过在锁目录下创建顺序节点来自然实现公平性,客户端只需检查是否有比自己序号小的节点存在即可。
8. 高可用性和容错性

重要性:
在分布式系统中,高可用性和容错性是评估分布式锁解决方案的关键指标。锁服务的任何故障都不应该影响整个系统的可用性。

提高策略:

  • 冗余部署: 使用如 Redis 集群或 Zookeeper 集群等,可以在多个节点上部署锁服务,以便在一个节点失败时其他节点可以接管功能。
  • 故障转移机制: 确保系统具备自动检测故障和重新选举或切换到备用系统的能力。
  • 数据持久化: 对于关键数据,应确保即使在系统崩溃后也能恢复状态,例如 Redis 的 AOF(Append Only File)持久化机制。

通过理解这些常见问题及其解决方案,可以更好地设计和实现一个稳定、可靠的分布式锁系统,从而保证分布式环境中资源的合理分配和高效使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/62304.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue+Elementui el-tree树只能选择子节点并且支持检索

效果&#xff1a; 只能选择子节点 添加配置添加检索代码 源码&#xff1a; <template><div><el-button size"small" type"primary" clearable :disabled"disabled" click"showSign">危险点评估</el-button>…

分析JHTDB数据库的Channel5200数据集的数据(SciServer服务器)

代码来自https://github.com/idies/pyJHTDB/blob/master/examples/channel.ipynb %matplotlib inline import numpy as np import math import random import pyJHTDB import matplotlib.pyplot as plt import time as ttN 3 T pyJHTDB.dbinfo.channel5200[time][-1] time …

《Vue零基础入门教程》第十二课:双向绑定指令

往期内容 《Vue零基础入门教程》第六课&#xff1a;基本选项 《Vue零基础入门教程》第八课&#xff1a;模板语法 《Vue零基础入门教程》第九课&#xff1a;插值语法细节 《Vue零基础入门教程》第十课&#xff1a;属性绑定指令 《Vue零基础入门教程》第十一课&#xff1a;事…

windows 应用 UI 自动化实战

UI 自动化技术架构选型 UI 自动化是软件测试过程中的重要一环&#xff0c;网络上也有很多 UI 自动化相关的知识或资料&#xff0c;具体到 windows 端的 UI 自动化&#xff0c;我们需要从以下几个方面考虑&#xff1a; 开发语言 毋庸置疑&#xff0c;在 UI 自动化测试领域&am…

linux部署Whisper 视频音频转文字

github链接&#xff1a;链接 我这里使用anaconda来部署&#xff0c;debian12系统&#xff0c;其他linux也同样 可以使用gpu或者cpu版本&#xff0c;建议使用n卡&#xff0c;rtx3060以上 一、前期准备 1.linux系统 链接&#xff1a;debian安装 链接&#xff1a;ubuntu安装 …

MySQL聚合查询分组查询联合查询

#对应代码练习 -- 创建考试成绩表 DROP TABLE IF EXISTS exam; CREATE TABLE exam ( id bigint, name VARCHAR(20), chinese DECIMAL(3,1), math DECIMAL(3,1), english DECIMAL(3,1) ); -- 插入测试数据 INSERT INTO exam (id,name, chinese, math, engli…

mini-spring源码分析

IOC模块 关键解释 beanFactory&#xff1a;beanFactory是一个hashMap, key为beanName, Value为 beanDefination beanDefination: BeanDefinitionRegistry&#xff0c;BeanDefinition注册表接口&#xff0c;定义注册BeanDefinition的方法 beanReference&#xff1a;增加Bean…

redis学习面试

1、数据类型 string 增删改查 set key valueget keydel kstrlen k 加减 incr articleincrby article 3decr articledecyby article 取v中特定位置数据 getrange name 0 -1getrange name 0 1setrange name 0 x 设置过期时间 setex pro 10 华为 等价于 set pro 华为expire pro…

详解MVC架构与三层架构以及DO、VO、DTO、BO、PO | SpringBoot基础概念

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 今天毛毛张分享的是SpeingBoot框架学习中的一些基础概念性的东西&#xff1a;MVC结构、三层架构、POJO、Entity、PO、VO、DO、BO、DTO、DAO 文章目录 1.架构1.1 基本…

KST-3D01型胎儿超声仿真体模、吸声材料以及超声骨密度仪用定量试件介绍

一、KST-3D01型胎儿超声仿真体模 KST—3D01型胎儿超声体模&#xff0c;采用仿羊水环境中内置胎龄为7个月大仿胎儿设计。用于超声影像系统3D扫描演示装置表面轮廓呈现和3D重建。仿羊水超声影像呈暗回声&#xff08;无回波&#xff09;特性&#xff0c;仿胎儿超声影像呈对比明显…

【逐行注释】自适应Q和R的AUKF(自适应无迹卡尔曼滤波),附下载链接

文章目录 自适应Q的KF逐行注释的说明运行结果部分代码各模块解释 自适应Q的KF 自适应无迹卡尔曼滤波&#xff08;Adaptive Unscented Kalman Filter&#xff0c;AUKF&#xff09;是一种用于状态估计的滤波算法。它是基于无迹卡尔曼滤波&#xff08;Unscented Kalman Filter&am…

易速鲜花聊天客服机器人的开发(上)

“聊天机器人”项目说明 聊天机器人&#xff08;Chatbot&#xff09;是LLM和LangChain的核心用例之一&#xff0c;很多人学习大语言模型&#xff0c;学习LangChain&#xff0c;就是为了开发出更好的、更能理解用户意图的聊天机器人。聊天机器人的核心特征是&#xff0c;它们可…

ChatGPT/AI辅助网络安全运营之-数据解压缩

在网络安全的世界中&#xff0c;经常会遇到各种压缩的数据&#xff0c;比如zip压缩&#xff0c;比如bzip2压缩&#xff0c;gzip压缩&#xff0c;xz压缩&#xff0c;7z压缩等。网络安全运营中需要对这些不同的压缩数据进行解压缩&#xff0c;解读其本意&#xff0c;本文将探索一…

05_JavaScript注释与常见输出方式

JavaScript注释与常见输出方式 JavaScript注释 源码中注释是不被引擎所解释的&#xff0c;它的作用是对代码进行解释。lavascript 提供两种注释的写法:一种是单行注释&#xff0c;用//起头:另一种是多行注释&#xff0c;放在/*和*/之间。 //这是单行注释/* 这是 多行 注释 *…

网络原理(一):应用层自定义协议的信息组织格式 HTTP 前置知识

目录 1. 应用层 2. 自定义协议 2.1 根据需求 > 明确传输信息 2.2 约定好信息组织的格式 2.2.1 行文本 2.2.2 xml 2.2.3 json 2.2.4 protobuf 3. HTTP 协议 3.1 特点 4. 抓包工具 1. 应用层 在前面的博客中, 我们了解了 TCP/IP 五层协议模型: 应用层传输层网络层…

题目 3209: 蓝桥杯2024年第十五届省赛真题-好数

一个整数如果按从低位到高位的顺序&#xff0c;奇数位&#xff08;个位、百位、万位 &#xff09;上的数字是奇数&#xff0c;偶数位&#xff08;十位、千位、十万位 &#xff09;上的数字是偶数&#xff0c;我们就称之为“好数”。给定一个正整数 N&#xff0c;请计算从…

数据结构与算法学习笔记----KMP

数据结构与算法学习笔记----KMP author: 明月清了个风 last edited: 2024.11.24 Acwing 831. KMP字符串 给定一个字符串 S S S&#xff0c;以及一个模式串 P P P&#xff0c;所有字符串中只包含大小写英文字母以及阿拉伯数字。 模式串 P P P在字符串 S S S中多次作为子串出…

算法基础 - 二分迭代法求解非线性方程

文章目录 1. 基本思想2. 编程实现2.1. 非递归2.2. 递归方案 3. 总结 二分迭代法使用了二分算法思想求解非线性方程式。 下面要求使用二分迭代法求解&#xff1a; 2x3-5x-10 方程式&#xff0c;且要求误差不能大于10e-5。 二分迭代法也只是近似求解算法。 所谓求解&#xff…

家校通小程序实战教程03学生管理

目录 1 创建数据源2 搭建后台功能3 设置主列字段4 批量导入数据5 设置查询条件6 实现查询和重置总结 我们现在已经搭建了班级管理&#xff0c;并且录入了班级口令。之后就是加入班级的功能了。这里分为老师加入班级和学生家长加入班级。 如果是学生家长的话&#xff0c;在加入之…

springboot336社区物资交易互助平台pf(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 社区物资交易互助平台设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff…