当前位置: 首页 > news >正文

八:分布式锁

1、为什么要使用分布式锁

  1. 锁是多线程代码中的概念,只有多任务访问同一个互斥的共享资源时才需要锁。
  2. 单机应用开发时一般使用synchronizedlock。多线程的运行都是在同一个JVM之下。
  3. 应用是分布式集群,属于多JVM的工作环境,JVM之间已经无法通过多线程的锁解决同步问题。

 

2、分布式锁的几种方式

分布式锁的核心思路是借助外力 解决多JVM进程操作共享数据时需要使用互斥锁的问题。

常见的方式 有:

  1. mysql数据库分布式锁
  2. zookeeper分布式锁
  3. redis分布式锁

3、搭建测试分布式锁的环境

【1】创建工程distributed-lock-study ,pom如下

父工程

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.6</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.lyx</groupId><artifactId>distributed-lock-study</artifactId><version>0.0.1-SNAPSHOT</version><packaging>pom</packaging><name>distributed-lock-study</name><description>distributed-lock-study</description><modules><module>moduleA</module><module>moduleB</module></modules><properties><java.version>8</java.version><dubbo.starter>2.7.6</dubbo.starter><dubbo.registry.zookeeper>2.7.6</dubbo.registry.zookeeper><mysql-connection.version>8.0.26</mysql-connection.version><druid.version>1.2.1</druid.version><mybatis-plus.version>3.5.2</mybatis-plus.version><hutool.version>5.7.17</hutool.version></properties>
<dependencyManagement><dependencies><!-- Dubbo 依赖 --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>${dubbo.starter}</version></dependency><!-- zookeeper 注册中心 依赖 --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-registry-zookeeper</artifactId><version>${dubbo.registry.zookeeper}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql-connection.version}</version><scope>runtime</scope></dependency><!--druid连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.version}</version></dependency><!--mybatis-plus依赖--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus.version}</version></dependency><!--hutool--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>${hutool.version}</version></dependency></dependencies></dependencyManagement></project>

 【2】创建moduleA和moduleB两个模块

依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.lyx</groupId><artifactId>distributed-lock-study</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>org.example</groupId><artifactId>moduleA</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--mybatis-plus依赖--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--druid连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId></dependency><!--redis依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--common-pool--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><!--  Redisson分布式锁使用--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.14.0</version></dependency><!--基于Curator 客户端(zookeeper的)实现分布式锁 --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.0.1</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.0.1</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

 【3】在两个模块中编写application.yml

spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/lock_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456redis:host: 192.168.184.200port: 6379lettuce:pool:max-active: 8max-idle: 8min-idle: 0max-wait: 100ms
server:port: 1111 # 两个模块的端口号不一样,其他一样

【4】编写启动类

@SpringBootApplication
@MapperScan("top.psjj.ma.mapper")
public class ModuleAApplication {public static void main(String[] args) {SpringApplication.run(ModuleAApplication.class,args);}
}

 【5】准备数据库local_db,并出入下张表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for t_goods
-- ----------------------------
DROP TABLE IF EXISTS `t_goods`;
CREATE TABLE `t_goods`  (`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',`goods` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,`count` int(0) NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of t_goods
-- ----------------------------
INSERT INTO `t_goods` VALUES (1, '手机', -1);
INSERT INTO `t_goods` VALUES (2, '笔记本', 100);SET FOREIGN_KEY_CHECKS = 1;

 【6】编写po 、mapper 、service 、controller,两个模块代码完全一样

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_goods")
public class Goods implements Serializable {@Serialprivate static final long serialVersionUID = -9084934747907815210L;@TableId(type = IdType.AUTO)private Integer id;private String goods;private Integer count;
}
public interface GoodsMapper extends BaseMapper<Goods> {@Update("update t_goods set count = count-1 where id=#{id}")void subCount(Integer id);
}
public interface GoodsService extends IService<Goods> {void updateGoodsCount(Integer id);
}
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {@Overridepublic void updateGoodsCount(Integer id) {Goods goods = this.baseMapper.selectById(id);Integer count = goods.getCount();if(count>0){try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}this.baseMapper.subCount(id);}}
}
@RestController
@RequestMapping("/goods")
public class GoodsController {@Autowiredprivate GoodsService goodsService;@RequestMapping("/update")public String updateGoodsCount(Integer id){goodsService.updateGoodsCount(id);return "ok";}
}

 

4、基于Mysql实现的分布式锁

4.1 mysql实现分布式锁原理

  • 首先单独分离出一台mysql数据库,所有服务要想操作文件(共享资源),那么必须先在mysql数据库中插入一个标志,插入标志的服务就持有了锁,并对文件进行操作
  • 操作完成后,主动删除标志进行锁释放,其余服务会一直查询数据库,看是否标志有被占用,直到没有标志占用时自己才能写入标志获取锁。

4.2  问题

  1. 如果服务(jvm1)宕机或者卡顿了,会一直持有锁未释放,造成死锁。因此需要一个监视锁进程,时刻监视锁的状态,如果超过一定时间未释放就要进行主动清理锁标记,然后供其他服务继续获取锁。
  2. 如果监视锁字段进程和jvm1同时挂掉,依旧不能解决死锁问题,于是又增加一个监视锁字段进程,这样一个进程挂掉,还有另一个监视锁字段进程可以对锁进行管理。
  3. 但是又诞生一个新的问题,两个监视进程必须进行同步,否则对于过期的情况管理存在不一致问题。

因此存在以下问题,并且方案变得很复杂:

  1. 监视锁字段进程对于锁的监视时间周期过短,仍旧会造成多售(jvm1还没处理完其持有的锁就被主动销毁,造成多个服务同时持有锁进行操作)。

  2. 监视锁字段进程对于锁的监视时间周期过长,会造成整个服务卡顿过长,吞吐低下。

  3. 多个监视锁字段进程间的同步问题

  4. 当一个jvm持有锁的时候,其余服务会一直访问数据库查看锁,会造成其余jvm的资源浪费

4.2 基于update实现分布锁(特殊情况)

关于分布式锁,因为代码直接执行语句,有数据库行级锁,不会产生超卖问题。

mysql行锁解决分布锁问题演示修改的代码: 

ServiceImpl中:

//mysql行锁解决分布锁问题
try {Thread.sleep(5000);
} catch (InterruptedException e) {throw new RuntimeException(e);
}
this.baseMapper.subCount2(goods);

mapper中: 

@Update("update t_goods set count=count-1 where id=#{id} and count>0")
void subCount2(Goods goods);

 

5、基于Redis实现分布式锁

 

5.1 Redis实现分布式锁优点

(1)Redis有很高的性能; 

(2)Redis命令对此支持较好,实现起来比较方便

命令介绍:

setnx :

SETNX key val:当且仅当key不存在时,set一个key为val的字符串,返回1;若key存在,则什么都不做,返回0。

expire :

expire key timeout:为key设置一个超时时间,单位为second,超过这个时间锁会自动释放,避免死锁。

delete :

 delete key:删除key

 在使用Redis实现分布式锁的时候,主要就会使用到这三个命令。

 

5.2 Redis实现分布式锁原理

  1. 获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间超过该时间则自动释放锁,锁的value值为一个随机生成的UUID,通过此在释放锁的时候进行判断。
  2. 获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁。
  3. 释放锁的时候,通过UUID判断是不是该锁,若是该锁,则执行delete进行锁释放

 

5.3 Redisson分布式锁使用

1)引入依赖

<!--  Redisson分布式锁使用-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.14.0</version>
</dependency>

2)配置文件

spring:redis:host: 192.168.220.110port: 6379

3)代码实现

//创建锁
RLock lock = redissonClient.getLock("goods-" + id);
//加锁
try {lock.lock();Goods goods = this.baseMapper.selectById(id);Integer count = goods.getCount();if(count>0){try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}this.baseMapper.subCount(id);}
} catch (RuntimeException e) {throw new RuntimeException("超卖了");
} finally {//释放锁lock.unlock();
}

5.4 总结

可以使用缓存代替数据库实现分布式锁,性能根号。同时多数缓存服务时集群部署,可以避免单点问题。

很多缓存服务提供了实现分布式锁的方法和对数据过期自动删除的支持,如Tair的put方法,redis 的setnx方法(Redisson是Redis官方推荐的Java版的Redis客户端) 。可以设置超时时间控制锁的释放。

使用缓存实现分布式锁的优点:性能好,实现起来较为方便。

使用缓存实现分布式锁的缺点通过超时时间来控制所得失效时间不靠谱。

6、 基于Zookeeper实现的分布式锁

6.1 Zookeeper的特点

Zookeeper的每一个节点,都是一个天然的顺序发号器,zookeeper有以下特点:

  1. 维护了一个有层次的数据节点,类似文件系统。

  2. 有临时节点,持久节点,临时有序节点(分布式锁实现基于的数据节点) ,持久有序节点。

  3. zookeeper可以和client客户端通过心跳机制保持长连接,断开连接自动删除临时节点。

  4. zookeeper的节点上可以注册上用户事件(自定义),节点数据删除等事件都可以触发自定义事件。

  5. zookeeper保持了统一视图,各服务对于状态信息获取满足一致性。

创建有序节点会有编号:

6.2 Zookeeper实现分布式锁原理

  1. 创建一个目录mylock;

  2. 线程A想获取锁就在mylock目录下创建临时顺序节点;

  3. 获取mylock目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁;

  4. 线程B获取所有节点,判断自己不是最小节点,设置监听比自己小的节点;

  5. 线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是不是最小的节点,如果是则获得锁。

6.3 Zookeeper解决的问题

锁无法释放?

在创建锁的时候,客户端会在ZK中创建一个临时节点,一旦客户端获取到锁之后突然挂掉(Session连接断开),那么这个临时节点就会自动删除掉锁就会释放

非阻塞锁?

客户端可以通过在ZK中创建顺序节点,并且在节点上绑定监听器,一旦节点有变化,Zookeeper会通知客户端,客户端可以检查自己创建的节点是不是序号最小,如果是,那么自己就获取到锁。

不可重入?  

客户端在创建节点的时候,把当前客户端的主机信息和线程信息直接写入到节点中下次想要获取锁的时候和当前最小的节点中的数据比对。如果信息一样直接获取到锁,如果不一样就再创建一个临时的顺序节点,参与排队。

单点问题?

ZK是集群部署的,只要集群中有半数以上的机器存活,就可以对外提供服务。  

6.4 基于Curator 客户端实现分布式锁

Curator Framework提供了简化使用zookeeper更高级的API接口。它包涵很多优秀的特性,主要包括以下三点

  1. 自动连接管理:自动处理zookeeper的连接和重试存在一些潜在的问题;可以watch NodeDataChanged event和获取updateServerList;Watches可以自动被Cruator recipes删除;

  2. 更干净的API:简化raw zookeeper方法,事件等;提供现代流式API接口

  3. Recipe实现:leader选举,分布式锁,path缓存,和watcher,分布式队列等。

 依赖:

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

代码:

//zookeeper 分布式锁解决超卖问题
//1.创建zookeeper连接
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client= CuratorFrameworkFactory.newClient("192.168.184.200:2181", retryPolicy);
client.start();
//创建分布式锁
InterProcessMutex interProcessMutex = new InterProcessMutex(client,"/ordersettinglock");
//加锁
try {interProcessMutex.acquire();Goods goods = this.baseMapper.selectById(id);Integer count = goods.getCount();if(count>0){try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}this.baseMapper.subCount(id);}
} catch (Exception e) {throw new RuntimeException("超卖了");
} finally {//释放锁try {interProcessMutex.release();} catch (Exception e) {throw new RuntimeException(e);}
}

6.5 总结

优点:

有效的解决单点问题、不可重入问题、非阻塞问题、锁无法释放问题。实现起来简单。

缺点:

性能上不如使用缓存实现分布式锁。需要对ZK的原理有所了解,比较复杂

7、分布式锁总结

上面几种方式,哪种方式都无法做到完美。就像CAP一样,在复杂性、可靠性、性能等方面无法同时满足,所以,根据不同的应用场景选择最适合自己的才是王道。

理解难易程度:

数据库>缓存(redis) >zookeeper.

复杂性:

zookeeper  >= 缓存 > 数据库

性能:

缓存 > zookeeper >= 数据库

可靠性:
zookeeper > 缓存 >数据库

相关文章:

八:分布式锁

1、为什么要使用分布式锁 锁是多线程代码中的概念&#xff0c;只有多任务访问同一个互斥的共享资源时才需要锁。单机应用开发时一般使用synchronized或lock。多线程的运行都是在同一个JVM之下。应用是分布式集群&#xff0c;属于多JVM的工作环境&#xff0c;JVM之间已经无法通过…...

示例:php将文本内容写入一个文件(面向过程写法)

一、封装2个函数&#xff0c;读写文件 /*** desc 读取文件内容* param string $filename* return array*/ private function readContent(string $filename): array {$text file_get_contents($filename);if (!$text) {return [];}$result json_decode($text,true);return…...

Flutter开发进阶之并发操作数据库

Flutter开发进阶之并发操作数据库 尽管 Flutter 本身不包含任何数据库功能&#xff0c;但可以使用各种第三方库和插件来在 Flutter 应用程序中实现数据库功能&#xff1b; 以下将使用sqflite作为例子&#xff0c;sqflite允许在 Flutter 应用程序中执行 SQL 查询&#xff0c;创…...

docker应用:搭建uptime-kuma监控站点

简介&#xff1a;Uptime Kuma是一个易于使用的自托管监控工具&#xff0c;它的界面干净简洁&#xff0c;部署和使用都非常方便。 历史攻略&#xff1a; docker&#xff1a;可视化工具portainer docker-compose&#xff1a;搭建自动化运维平台Spug 开源地址&#xff1a; ht…...

在illustrator中按大小尺寸选择物体 <脚本 018>

在Illustrator中我们可以依据对象的属性 如&#xff1a;填充颜色、描边颜色或描边宽度来选择相同属性的对象&#xff0c;但是Illustrator中没有根据不同大小尺寸来选择对象的功能&#xff0c;下面介绍的就是根据大小尺寸选择对象的脚本。 1、下面是当前画板中的所有对象&#…...

leetcode - 934. Shortest Bridge

Description You are given an n x n binary matrix grid where 1 represents land and 0 represents water. An island is a 4-directionally connected group of 1’s not connected to any other 1’s. There are exactly two islands in grid. You may change 0’s to 1…...

k8s的存储卷、数据卷

容器内的目录和宿主机目录进行挂载。 容器在系统上的生命周期是短暂的。 k8s用控制器创建的pod。delete相当于重启。容器的状态也会恢复到初始状态。一旦恢复到初始状态&#xff0c;所有的后天编辑的文件都会消失 容器和节点之间创建一个可以持久化保存容器内文件的存储卷。…...

流星全自动网页生成系统重构版源码

流星全自动网页生成系统重构版源码分享&#xff0c;所有模板经过精心审核与修改&#xff0c;完美兼容小屏手机大屏手机&#xff0c;以及各种平板端、电脑端和360浏览器、谷歌浏览器、火狐浏览器等等各大浏览器显示。 为用户使用方便考虑&#xff0c;全自动网页制作系统无需繁琐…...

vscode打开c_cpp_properties.json文件的一种方式

步骤一 点击win32 步骤二 点击json 自动生成了...

发起人自选-钉钉审批

场景描述 配置一个审批流程&#xff0c;在某些审批节点&#xff0c;不能确定谁具体来审批&#xff0c;所以需要手工选择一个人或者多个人保证流程能得以顺利通过。有些审批流程的做法是&#xff0c;上一个节点来选择指定的人&#xff0c;而钉钉的做法是发起人来指定。 钉钉设…...

电脑DIY-显卡

显卡 英伟达&#xff08;NVIDIA&#xff09;RTX系列 英伟达&#xff08;NVIDIA&#xff09; 英伟达&#xff08;NVIDIA&#xff09;是一家知名的图形处理器制造商&#xff0c;其显卡产品系列众多。以下是英伟达显卡的主要系列&#xff1a; 系列面向客户说明产品GeForce系列个…...

vue3+vite+ts+pinia新建项目(略详细版)

1、新建项目 npm create vite@latest 2、安装依赖 yarn add vue-router yarn add -D @types/node vite-plugin-pages sass sass-loader 3、配置别名 //vite.config.ts import { defineConfig } from vite import path from node:path export default defineConfig({ plu…...

深入理解 Flink(五)Flink Standalone 集群启动源码剖析

前言 Flink 集群的逻辑概念&#xff1a; JobManager(StandaloneSessionClusterEntrypoint) TaskManager(TaskManagerRunner) Flink 集群的物理概念&#xff1a; ResourceManager(管理集群所有资源&#xff0c;管理集群所有从节点) TaskExecutor(管理从节点资源&#xff0c;接…...

SpringCloud Aliba-Nacos-从入门到学废【2】

&#x1f95a;今日鸡汤&#x1f95a; 比起不做而后悔&#xff0c;不如做了再后悔。 ——空白《游戏人生》 目录 &#x1f9c8;1.Nacos集群架构说明 &#x1f9c2;2.三种部署模式 &#x1f37f;3.切换到mysql 1.在nacos-server-2.0.3\nacos\conf里找到nacos-mysql.sql 2.查…...

web前端算法简介之字典与哈希表

回顾 栈、队列 &#xff1a; 进、出 栈&#xff08;Stack&#xff09;&#xff1a; 栈的操作主要包括&#xff1a; 队列&#xff08;Queue&#xff09;&#xff1a; 队列的操作主要包括&#xff1a; 链表、数组 &#xff1a; 多个元素存储组成的 简述链表&#xff1a;数组&…...

【uview2.0】Keyboard 键盘 与 CodeInput 验证码输入 结合使用 uview

https://www.uviewui.com/components/codeInput.html &#xff08;CodeInput 验证码输入&#xff09; https://www.uviewui.com/components/keyboard.html &#xff08;Keyboard 键盘&#xff09; <u-keyboard mode"number" :dotDisabled"true" :show&q…...

解决chromebook kabylake安装linux没有声音问题

chromebook kabylake安装arch没有声音&#xff0c;好长时间没有解决&#xff0c;一直用的蓝牙耳机。 今天搜搜帖子解决了&#xff0c; 分享供参考 git clone https://github.com/eupnea-project/chromebook-linux-audiocd chromebook-linux-audio ./setup-audio提示 I Underst…...

Spring Boot - Application Events 的发布顺序_ApplicationContextInitializedEvent

文章目录 Pre概述Code源码分析 Pre Spring Boot - Application Events 的发布顺序_ApplicationEnvironmentPreparedEvent Spring Boot - Application Events 的发布顺序_ApplicationEnvironmentPreparedEvent 概述 Spring Boot 的广播机制是基于观察者模式实现的&#xff0c…...

由jar包冲突导致的logback日志不输出

最近接手一个厂商移交的项目&#xff0c;发现后管子系统不打印日志。 项目使用的logback 本地断点调试发现logback-classic jar冲突导致 打出的war中没有 相关的jar 解决方法&#xff1a; 去除pom 文件中多余的 logback-classic 应用&#xff0c;只保留最新版本的。 重新打…...

app开发——安卓native开发思路记录

我们知道app开发目前有三种方式&#xff0c;第一种是webapp&#xff0c;第二种是hybird app&#xff0c;第三种是native app。 而native-app就是安卓原生app&#xff0c;这里记录一下安卓原生开发的基本思路。 首先&#xff0c;安卓原生开发虽然在当今时代不是那么常见了&…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...