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

java分布式锁分布式锁

java分布式&锁&分布式锁

  1. 锁的作用:有限资源的情况下,控制同一时间段,只有某些线程(用户/服务器)能访问到资源。
    在这里插入图片描述
  2. 锁在java中的实现:
    • synchronized关键字
    • 并发包的类
  3. 缺点:只对单个的jvm有效
    在这里插入图片描述

分布式锁

  1. 为什么实现分布式锁
    • 有限资源的情况下,控制同一段时间只有某些用户/服务器才能访问到资源
    • 单个锁只对单个jvm有效
  2. 分布锁实现(核心思想,先来server把数据改成自己的标识,后来的人发现标识已经存在就等待)
    • 抢锁机制 ==> 同一时间只有一个服务器能抢到资源 ==>
      1. Mysql数据库实现,数据库中有一个字段标识锁,哪个服务器先到达数据库,就将此标识改为自己服务器的值,下一个服务器查到达查看不为空就等待,知道此上一个服务器用完,将标识位改为空时,方可用。
        • 查select(控制只有一个服务器在查)(1.select for update 行级锁,2.乐观锁)
        • 改update
      2. redis实现,存标识。读写速度快,支持setnx,lua脚本实现
        • 原理:使用redis的setnx方法保证原子性质
          setnx:set if not exist如果不存在,则设置,只有设置成功才会返回true,否则返回false
          在这里插入图片描述
        • 注意1: 用完锁之后要释放,防止在释放之前服务器出现意外,因此要设置过期时间
        • 注意2:如果方法执行时间过长,锁提前过期,出现多个服务器同时执行。=> 续期(redisson中提供续期机制,原理:监听当前线程,默认过期时间是30s,每10s续期一次(补充到30s),如果线程挂了,则不会续期,如果debug模式也会被当成服务器宕机)。
        • 注意3:连锁效应:释放了其他server的锁 .=> 判断如果不是我的锁就不释放
        • 注意4:释放锁的时候,有可能先判断出是自己的锁,但是这时候锁过期了,会释放其他服务器/用户的锁 => 判断和释放的时候不允许其他任何的方法进入,redis原子性操作。配合redis+lua脚本。
    1. Zookeeper实现

控制定时任务的执行(在同一时间只有一个服务器能执行)

  1. 原因:

    • 浪费资源,假设有1000台服务器同时工作
    • 脏数据
      在这里插入图片描述
  2. 实现方式

    1. 分离定时任务,把控制定时任务从主程序中拆开(成本太大)
      在这里插入图片描述

    2. 配置,写死配置,每个服务器都执行定时任务,但是只有ip符合配置的才真实执行业务逻辑,其他的直接返回。
      在这里插入图片描述

    3. ☆动态配置,这个配置是可以轻松的跟新的,把配置写到数据库,Redis,配置中心(Nacos,Apollo,spring Cloud config)(问题:如果服务器数据太多,ip不可控制)
      在这里插入图片描述

    4. 分布式锁【只有抢到锁的服务器才能执行定时任务】

      在这里插入图片描述

Reddisson实现分布式锁

  1. Redisson:是一个java操作Redis的客户端,提供了大量的分布式数据集来简化对Redis的操作和使用,可以让开发者像使用本地集合一样使用Redis,完全感觉不到Redis的存在。
    redisson官网:redisson
  2. Redisson使用方法
    1. 支持springboot整合Rdisson,写配置,默认整合客户端。(版本迭代太快)
    2. 只引入Redisson,自己创建客户端
      1. 引入项目依赖Redisson类库
         <!--https://github.com/redisson/redisson#quick-start--><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.21.3</version></dependency>
        
      2. 新建redisson客户端
        /*** redisson配置*/
        @Configuration
        @ConfigurationProperties(prefix = "spring.redis")
        @Data
        public class RedissonConfig {private String host;private String port;@Beanpublic RedissonClient redissonClient(){// 1. 创建配置对象Config config = new Config();String redisAddress = String.format("redis://%s:%s",host,port);config.useSingleServer().setAddress(redisAddress).setDatabase(3);// 2. 创建实例RedissonClient redisson = Redisson.create(config);return redisson;}
        }
        
      3. 使用锁实现缓存预热
        waitTime = 0 只抢一次
        /*** 缓存预热任务*/
        @Slf4j
        public class PreCacheJob {@Resourceprivate RedisTemplate<String, Object> redisTemplate;@Resourceprivate UserService userService;@Resourcepublic UserMapper userMapper;//重点用户private List<Long> mainUserList = Arrays.asList(1L);//引入redisson客户端@Resourceprivate RedissonClient redissonClient;//每天执行,预热推荐用户@Scheduled(cron = "0 31 19 * * ? ")public void doCacheRecommendUser() {RLock lock = redissonClient.getLock("yupao:precachejob:docache:lock");try {//waitTime:其他线程等待的时间,因为我们缓存预热每天只做一次,所以只要有一个线程拿到锁就//leaseTime:锁过期时间if (lock.tryLock(0, 30000L, TimeUnit.MILLISECONDS)) {//是否拿到锁for (Long userId : mainUserList) {QueryWrapper<User> queryWrapper = new QueryWrapper<>();Page<User> userPage = userService.page(new Page<>(1, 20),queryWrapper);String redisKey = String.format("yupao:user:recommend:%s", userId);ValueOperations<String, Object> valueOperations =redisTemplate.opsForValue();//写缓存try {valueOperations.set(redisKey, userPage, 30000,TimeUnit.MILLISECONDS);} catch (Exception e) {log.error("redis set key error", e);}}}} catch (InterruptedException e) {log.error("doCacheRecommendUser error",e);} finally {//释放自己的锁if (lock.isHeldByCurrentThread()) {//是否是当前线程System.out.println("unlock: " + Thread.currentThread().getId());lock.unlock();}}}
        }

相关文章:

java分布式锁分布式锁

java分布式&锁&分布式锁 锁 锁的作用&#xff1a;有限资源的情况下&#xff0c;控制同一时间段&#xff0c;只有某些线程&#xff08;用户/服务器&#xff09;能访问到资源。 锁在java中的实现&#xff1a; synchronized关键字并发包的类 缺点&#xff1a;只对单个的…...

2. 流程控制|方法|数组|二维数组|递归

文章目录 流程控制代码块选择结构循环结构跳转控制关键字 方法方法的概述方法的重载Junit单元测试初识全限定类名 Debug 小技巧数组数组的基本概念数组的基本使用数组的声明数组的初始化 JVM内存模型什么是引用数据类型基本数据类型和引用数据类型的区别堆和栈中内容的区别 数组…...

22. 自动装配有哪些限制(需要注意)?

自动装配有哪些限制(需要注意)&#xff1f; 一定要声明set方法覆盖&#xff1a; 你仍可以用 < constructor-arg >和 < property > 配置来定义依赖&#xff0c;这些配置将始终覆盖自动注入。基本数据类型&#xff1a;不能自动装配简单的属性&#xff0c;如基本数据…...

14 网关实战:网关聚合API文档

上节课介绍了网关层的认证鉴权,今天这节介绍一下网关层如何聚合API接口文文档。 为什么需要聚合API接口文档? 大型微服务系统模块众多,木谷博客系统就有9个,如果这些服务的接口地址没有一个统一,那么客户端将要保存每个服务的接口地址,这个肯定是不现实。 先来看一下A…...

css 固定按钮到页面顶部或者底部的实现方式

实现方式 要将按钮固定到顶部或底部&#xff0c;可以使用CSS的定位属性来实现。下面是一种常用的方法&#xff1a; 创建一个包含按钮的HTML元素&#xff0c;例如一个<div>元素。确保给它添加一个唯一的id&#xff0c;以便在CSS中进行定位。 <div id"myButton&qu…...

【Java Spring】SpringBoot常用插件

文章目录 1、Lombok1.1 IDEA社区版安装Lombok1.2 IDEA专业版安装Lombok1.3 Lombok的基本使用 2、EditStarters2.1 IDEA安装EditStarters2.2 EditStarters基本使用方法 1、Lombok 是简化Java开发的一个必要工具&#xff0c;lombok的原理是编译过程中将lombok的注解给去掉并翻译…...

GPT还远远不是真正的智能

GPT是一个基于深度学习的自然语言处理模型&#xff0c;它可以生成逼真的文本。虽然GPT在生成文本方面取得了显著的进展&#xff0c;但它并不具备真正的智能。GPT是通过训练模型来学习语言模式&#xff0c;它不具备理解、推理、判断和主动学习的能力。它只是根据已有的语料库生成…...

计算机网络:网络层

0 本节主要内容 问题描述 解决思路 1 问题描述 两大问题&#xff08;重点&#xff0c;也是难点&#xff09;&#xff1a; 地址管理&#xff1b;路由选择。 1.1 子问题1&#xff1a;地址管理 网络上的这些主机和节点都需要使用一种规则来区分&#xff0c;就相当于是一种身…...

消息队列进阶-1.消息队列的应用场景与选型

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理&#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44…...

浅谈堆和栈内存以及编程语言

浅谈堆和栈内存以及编程语言 栈和堆C 和 C# 的区别&#xff1a;C#总结 编程语言C汇编语言&#xff08;Assembly Language&#xff09;&#xff1a;机器语言&#xff08;Machine Language&#xff09;&#xff1a; 拓展C#依赖注入&#xff08;Dependency Injection&#xff09;模…...

SpringBootWeb案例_01

Web后端开发_04 SpringBootWeb案例_01 原型展示 成品展示 准备工作 需求&环境搭建 需求说明&#xff1a; 完成tlias智能学习辅助系统的部门管理&#xff0c;员工管理 环境搭建 准备数据库表&#xff08;dept、emp&#xff09;创建springboot工程&#xff0c;引入对应…...

C语言数据结构-----栈和队列练习题(分析+代码)

前言 前面的博客写了如何实现栈和队列&#xff0c;下来我们来看一下队列和栈的相关习题。 链接: 栈和队列的实现 文章目录 前言1.用栈实现括号匹配2.用队列实现栈3.用栈实现队列4.设计循环队列 1.用栈实现括号匹配 此题最重要的就是数量匹配和顺序匹配。 用栈可以完美的做到…...

uniapp基础-教程之HBuilderX配置篇-01

uniapp教程之HBuilderX配置篇-01 为什么要做这个教程的梳理&#xff0c;主要用于自己学习和总结&#xff0c;利于增加自己的积累和记忆。首先下载HBuilderX&#xff0c;并保证你的软件在C盘进行运行&#xff0c;最好使用英文或者拼音&#xff0c;这个操作是为了保证软件的稳定…...

【备忘录】快速回忆ElasticSearch的CRUD

导引——第一条ElasticSearch语句 测试分词器 POST /_analyze {"text":"黑马程序员学习java太棒了","analyzer": "ik_smart" }概念 语法规则 HTTP_METHOD /index/_action/IDHTTP_METHOD 是 HTTP 请求的方法&#xff0c;常见的包括…...

影响PPC广告成本预算的因素,如何计算亚马逊PPC广告预算——站斧浏览器

亚马逊PPC&#xff0c;又称按点击付费(Pay Per Click)&#xff0c;是一种只有用户点击你的广告时才会向你收费的模式。那么影响PPC广告成本预算的因素,如何计算亚马逊PPC广告预算&#xff1f; 影响PPC广告成本预算的因素 1、产品类别&#xff1a;不同类别的产品竞争程度不同&…...

Qt 信号和槽

目录 概念 代码 mainwindow.h me.h xiaohuang.h main.cc mainwindow.cc me.cc xianghuang.cc mainwindow.ui 自定义信号的要求和注意事项: 自定义槽的要求和注意事项: 概念 信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽&#xff0c;实际就是观察者模式(发布-订…...

Linux基本命令二

Linux基本命令二 1、head 命令 head ​ **作用&#xff1a;**用于查看文件的开头部分的内容&#xff0c;有一个常用的参数 -n 用于显示行数&#xff0c;默认为 10&#xff0c;即显示 10 行的内容 ​ **语法&#xff1a;**head [参数] [文件] ​ 命令参数&#xff1a; 参数…...

isbn api开放接口

接口地址&#xff1a;http://openapi.daohe168.com.cn/api/library/isbn/query?isbn9787115618085&appKeyd7c6c07a0a04ba4e65921e2f90726384 响应结果&#xff1a; { "success": true, "code": "200", "message": …...

助力企业实现更简单的数据库管理,ATOMDB 与 TDengine 完成兼容性互认

为加速数字化转型进程&#xff0c;当下越来越多的企业开始进行新一轮数据架构改造升级。在此过程中&#xff0c;全平台数据库管理客户端提供了一个集中管理和操作数据库的工具&#xff0c;提高了数据库管理的效率和便利性&#xff0c;减少了人工操作的复杂性和错误率&#xff0…...

如何通过低代码工具,提升运输行业的运营效率和服务质量

《中国数字货运发展报告》显示&#xff0c;2022年我国公路货运市场规模在5万亿元左右。其中&#xff0c;数字货运整体市场规模约为7000亿元&#xff0c;市场渗透率约为15%。而以小微企业为主的货运行业&#xff0c;却以小、散、乱的行业特征&#xff0c;承载着5万亿元左右的市场…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...