IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> redis实现分布式锁 -> 正文阅读

[大数据]redis实现分布式锁

1.什么是分布式锁?

1.1 情景

假设,对一个商品表的简单操作,一个线程去修改这个商品的信息,首先得从数据库中查出这条数据,然后加载在内存中,在内存修改完成之后,再存到数据库里面,对于单线程而言这一个完整的操作是没问题的,但是在多线程中,由于读取,修改,保存到数据库不是原子操作(原子特性:不可分割,要么全都成功,要么全都失败),所以这种操作出现在多线程中就会有很大的问题。

1.2 用redis实现分布式锁的思路?

分布式锁的思路不难,其实就是先进来的线程先占位置,当其他线程进来时,发现位置被人占了,就会放弃争夺或者稍后再来争夺。

在redis中,用setnx命令和del命令,可以简单的实现分布式锁,setnx命令返回1就代表线程抢到锁了,setnx命令返回0代表线程没抢到锁,del命令可以释放锁

2. 简单实现

2.1 jedisutils

package com.yl;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class JedisUtils {
    private static JedisPool jedisPool = null;

    public static Jedis getJedisObject() {
        if (jedisPool == null) {
            GenericObjectPoolConfig config = new GenericObjectPoolConfig();
            //最大空闲数
            config.setMaxIdle(400);
            //最大连接数
            config.setMaxTotal(2000);
            //连接最大等待时间,-1代表没有限制
            config.setMaxWaitMillis(300000);
            /**
             * 配置连接池的地址,端口号,超时时间,密码
             */
            jedisPool = new JedisPool(config,"192.168.244.129",6379,30000,"root123");
        }
        try {
            //通过连接池获取jedis对象
            Jedis jedis = jedisPool.getResource();
            jedis.auth("root123");
            return jedis;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

2.1 测试

package com.yl;

import redis.clients.jedis.Jedis;

public class LockTest {
    public static void main(String[] args) {
        Jedis jedis = JedisUtils.getJedisObject();
        Long setnx = jedis.setnx("k1", "v1");
        if (setnx == 1) {
            //没人占位
            //有可能没有执行到del那一步,所以给锁添加过期时间
            jedis.expire("k1",5);
            jedis.set("name", "yl");
            String name = jedis.get("name");
            System.out.println(name);
            //释放资源
            jedis.del("k1");
        } else {
            //有人占位,停止操作
            System.out.println("没有获取到锁!");
        }
    }
}

3. (2.0简单实现分布锁)存在的问题以及解决方案

3.1 存在的问题

从2.0可以看到,获取到锁后,要设置过期时间(设置过期时间是预防业务代码出错,锁一直没释放掉!),那么这里会出现一种情况,假设这个过期时间设得比较小,然后,线程一进来了,执行它自己的业务代码,很复杂,执行得很慢,花费的时间远大于锁的超时时间,这个时候,线程一还在执行自己的业务代码,线程二抢到了锁进来了,然后也执行自己的业务代码,执行到一半,线程一的业务代码执行完了,线程二的还没执行完,线程一按道理还是会去释放锁的,这个时候线程二是锁的拥有者,线程一释放掉线程二的锁,这种情况合理?显然不合理,2.0中锁的value都固定为v1,所以它们公用同一个锁,且它们的value都是一样的!

3.2 解决方案:锁的value用随机字符串来替代再结合lua脚本判断传入的key去redis中查到的value和传入的value是否一致,如果一致就del掉key,否则直接返回

3.2.1 进入到redis文件,创建脚本文件

mkdir lua
cd lua/
vi release.lua

3.2.2 release.lua脚本文件内容

if redis.call("get",KEYS[1])==ARGV[1]then
   return redis.call("del",KEYS[1])
else
   return 0
end

3.2.3 求出SHA1和,作用:将lua脚本文件加载到redis缓存中,并且返回一个参数,在调用lua脚本时要传这个参数

cat lua/release.lua | redis-cli -a root123 script load --pipe

在这里插入图片描述

3.2.4 测试

package com.yl;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

import java.util.Arrays;
import java.util.UUID;

public class LockTest3 {
    public static void main(String[] args) {
        Jedis jedis = JedisUtils.getJedisObject();
        //1.先随机获取一个字符串
        String str= UUID.randomUUID().toString();
        //2.获取锁,并且设置过期时间为5秒
        String lock = jedis.set("k1", str, new SetParams().nx().ex(5));
        //3.是否拿到锁
        if (lock != null && "OK".equals(lock)) {
            //成功拿到锁
            //4.具体业务写这里
            jedis.set("name","yl");
            jedis.set("age","23");
            System.out.println(jedis.get("name"));
            System.out.println(jedis.get("age"));

            //5.调用lua脚本,释放自己的锁
            jedis.evalsha("b8059ba43af6ffe8bed3db65bac35d452f8115d8", Arrays.asList("k1"),Arrays.asList(str));

        } else {
            //没获取到锁
            System.out.println("没有获取到锁!");
        }
    }
}

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-10-09 16:21:04  更:2021-10-09 16:21:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:03:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码