`
frank1998819
  • 浏览: 758429 次
  • 性别: Icon_minigender_1
  • 来自: 南京
文章分类
社区版块
存档分类

分布式锁的作用及实现(Redis)(转)

 
阅读更多

一、什么是分布式锁?

要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁、进程锁。

 

线程锁:主要用来给方法、代码块加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synchronized是共享对象头,显示锁Lock是共享某个变量(state)。

 

进程锁:为了控制同一操作系统中多个进程访问某个共享资源,因为进程具有独立性,各个进程无法访问其他进程的资源,因此无法通过synchronized等线程锁实现进程锁。

 

分布式锁:当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问。

 

二、分布式锁的使用场景。

线程间并发问题和进程间并发问题都是可以通过分布式锁解决的,但是强烈不建议这样做!因为采用分布式锁解决这些小问题是非常消耗资源的!分布式锁应该用来解决分布式情况下的多进程并发问题才是最合适的。

 

有这样一个情境,线程A和线程B都共享某个变量X。

 

如果是单机情况下(单JVM),线程之间共享内存,只要使用线程锁就可以解决并发问题。

 

如果是分布式情况下(多JVM),线程A和线程B很可能不是在同一JVM中,这样线程锁就无法起到作用了,这时候就要用到分布式锁来解决。

 

三、分布式锁的实现(Redis)

分布式锁实现的关键是在分布式的应用服务器外,搭建一个存储服务器,存储锁信息,这时候我们很容易就想到了Redis。首先我们要搭建一个Redis服务器,用Redis服务器来存储锁信息。

 

在实现的时候要注意的几个关键点:

 

1、锁信息必须是会过期超时的,不能让一个线程长期占有一个锁而导致死锁;

 

2、同一时刻只能有一个线程获取到锁。

 

几个要用到的redis命令:

 

setnx(key, value):“set if not exits”,若该key-value不存在,则成功加入缓存并且返回1,否则返回0。

 

get(key):获得key对应的value值,若不存在则返回nil。

 

getset(key, value):先获取key对应的value值,若不存在则返回nil,然后将旧的value更新为新的value。

 

expire(key, seconds):设置key-value的有效期为seconds秒。

 

看一下流程图:

 

 

 

在这个流程下,不会导致死锁。

 

我采用Jedis作为Redis客户端的api,下面来看一下具体实现的代码。

 

(1)首先要创建一个Redis连接池。

 

public class RedisPool {

 

    private static JedisPool pool;//jedis连接池

 

    private static int maxTotal = 20;//最大连接数

 

    private static int maxIdle = 10;//最大空闲连接数

 

    private static int minIdle = 5;//最小空闲连接数

 

    private static boolean testOnBorrow = true;//在取连接时测试连接的可用性

 

    private static boolean testOnReturn = false;//再还连接时不测试连接的可用性

 

    static {

        initPool();//初始化连接池

    }

 

    public static Jedis getJedis(){

        return pool.getResource();

    }

 

    public static void close(Jedis jedis){

        jedis.close();

    }

 

    private static void initPool(){

        JedisPoolConfig config = new JedisPoolConfig();

        config.setMaxTotal(maxTotal);

        config.setMaxIdle(maxIdle);

        config.setMinIdle(minIdle);

        config.setTestOnBorrow(testOnBorrow);

        config.setTestOnReturn(testOnReturn);

        config.setBlockWhenExhausted(true);

        pool = new JedisPool(config, "127.0.0.1", 6379, 5000, "liqiyao");

    }

}

(2)对Jedis的api进行封装,封装一些实现分布式锁需要用到的操作。

 

public class RedisPoolUtil {

 

    private RedisPoolUtil(){}

 

    private static RedisPool redisPool;

 

    public static String get(String key){

        Jedis jedis = null;

        String result = null;

        try {

            jedis = RedisPool.getJedis();

            result = jedis.get(key);

        } catch (Exception e){

            e.printStackTrace();

        } finally {

            if (jedis != null) {

                jedis.close();

            }

            return result;

        }

    }

 

    public static Long setnx(String key, String value){

        Jedis jedis = null;

        Long result = null;

        try {

            jedis = RedisPool.getJedis();

            result = jedis.setnx(key, value);

        } catch (Exception e){

            e.printStackTrace();

        } finally {

            if (jedis != null) {

                jedis.close();

            }

            return result;

        }

    }

 

    public static String getSet(String key, String value){

        Jedis jedis = null;

        String result = null;

        try {

            jedis = RedisPool.getJedis();

            result = jedis.getSet(key, value);

        } catch (Exception e){

            e.printStackTrace();

        } finally {

            if (jedis != null) {

                jedis.close();

            }

            return result;

        }

    }

 

    public static Long expire(String key, int seconds){

        Jedis jedis = null;

        Long result = null;

        try {

            jedis = RedisPool.getJedis();

            result = jedis.expire(key, seconds);

        } catch (Exception e){

            e.printStackTrace();

        } finally {

            if (jedis != null) {

                jedis.close();

            }

            return result;

        }

    }

 

    public static Long del(String key){

        Jedis jedis = null;

        Long result = null;

        try {

            jedis = RedisPool.getJedis();

            result = jedis.del(key);

        } catch (Exception e){

            e.printStackTrace();

        } finally {

            if (jedis != null) {

                jedis.close();

            }

            return result;

        }

    }

}

(3)分布式锁工具类

 

public class DistributedLockUtil {

 

    private DistributedLockUtil(){

    }

 

    public static boolean lock(String lockName){//lockName可以为共享变量名,也可以为方法名,主要是用于模拟锁信息

        System.out.println(Thread.currentThread() + "开始尝试加锁!");

        Long result = RedisPoolUtil.setnx(lockName, String.valueOf(System.currentTimeMillis() + 5000));

        if (result != null && result.intValue() == 1){

            System.out.println(Thread.currentThread() + "加锁成功!");

            RedisPoolUtil.expire(lockName, 5);

            System.out.println(Thread.currentThread() + "执行业务逻辑!");

            RedisPoolUtil.del(lockName);

            return true;

        } else {

            String lockValueA = RedisPoolUtil.get(lockName);

            if (lockValueA != null && Long.parseLong(lockValueA) >= System.currentTimeMillis()){

                String lockValueB = RedisPoolUtil.getSet(lockName, String.valueOf(System.currentTimeMillis() + 5000));

                if (lockValueB == null || lockValueB.equals(lockValueA)){

                    System.out.println(Thread.currentThread() + "加锁成功!");

                    RedisPoolUtil.expire(lockName, 5);

                    System.out.println(Thread.currentThread() + "执行业务逻辑!");

                    RedisPoolUtil.del(lockName);

                    return true;

                } else {

                    return false;

                }

            } else {

                return false;

            }

        }

    }

}

 

--------------------- 

作者:LiQiyaoo 

来源:CSDN 

原文:https://blog.csdn.net/l_bestcoder/article/details/79336986 

版权声明:本文为博主原创文章,转载请附上博文链接!

 

分享到:
评论

相关推荐

    redis实现分布式锁,自旋式加锁,lua原子性解锁

    Redis中的分布式锁实现通常基于`SETNX`命令或`SET`命令的`nx`与`ex`组合。`SETNX`命令用于设置键值,但如果键已经存在,则不执行任何操作,这可以确保锁的互斥性。`SET key value EX timeout NX`则同时设置了超时...

    Java基于redis实现分布式锁代码实例

    Java基于Redis实现分布式锁代码实例 分布式锁的必要性 在多线程环境中,资源竞争是一个常见的问题。例如,在一个简单的用户操作中,一个线程修改用户状态,首先在内存中读取用户状态,然后在内存中进行修改,然后...

    C++基于redis的分布式锁redisAPI

    本文将深入探讨如何使用C++结合Redis实现分布式锁,并详细讲解Redis API在C++中的应用,以及如何处理与Boost库的集成。 首先,Redis是一个高性能的键值存储数据库,广泛用于缓存、消息队列、分布式锁等场景。分布式...

    redis分布式锁工具类

    现在很多项目单机版已经不满足了,分布式变得越受欢迎,同时也带来很多问题,分布式锁也变得没那么容易实现,分享一个redis分布式锁工具类,里面的加锁采用lua脚本(脚本比较简单,采用java代码实现,无须外部调用...

    记录redisson实现redis分布式事务锁

    分布式锁的主要作用是在多节点环境下保证同一时刻只有一个节点可以执行特定操作,避免并发问题。Redisson的分布式锁通过`RLock`接口提供,它实现了Lock接口,包含了常规锁的基本功能,如`lock()`, `unlock()`等。 ...

    分布式锁实现(基于redis-mysql)1

    本文主要探讨了三种常见的分布式锁实现方式,包括基于Redis、MySQL以及Zookeeper的实现方法。 **基于Redis实现分布式锁** Redis是一个内存数据库,其命令执行是单线程的,这使得它非常适合用来实现分布式锁。Redis...

    C#实操控制并发之Lock和Redis分布式锁

    以下是一个简单的C# Redis分布式锁实现: ```csharp public bool TryAcquireLock(string lockKey, int lockTimeout) { var redis = ConnectionMultiplexer.Connect("localhost:6379"); var db = redis.Get...

    基于Redis方式实现分布式锁

    以下是一个简单的Java示例,展示了如何使用Jedis客户端库来实现Redis分布式锁。 ```java public class RedisLock { private JedisPool jedisPool; public RedisLock(JedisPool jedisPool) { this.jedisPool = ...

    redis分布式锁实现抢单秒杀

    在IT行业中,尤其是在高并发的电子商务系统中,"redis分布式锁实现抢单秒杀"是一个常见的挑战。这个场景模拟了多个用户同时参与秒杀活动,系统需要确保库存的准确性和抢单的公平性,避免超卖和数据不一致的问题。...

    C#.net Redis分布式锁源码实现

    本篇文章将深入探讨如何在C#.NET环境下利用Redis实现分布式锁,以及相关的核心知识点。 首先,让我们理解什么是分布式锁。分布式锁是在分布式系统中,用于协调不同节点间对共享资源访问的一种工具。它确保在任何...

    redis分布式锁.zip

    Redis 的高可用性和低延迟特性使其成为实现分布式锁的理想选择。下面将详细介绍如何使用 Redis 实现分布式锁以及其中可能遇到的问题和解决方案。 首先,我们需要理解分布式锁的基本概念。分布式锁是一种在分布式...

    springboot基于redis分布式锁

    以下是一个简单的Spring Data Redis的分布式锁实现示例: ```java import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; @Component public class...

    redis实现分布式锁(java/jedis)

    redis实现分布式锁(java/jedis),其中包含工具方法以及使用demo 本资源是利用java的jedis实现 redis实现分布式锁(java/jedis),其中包含工具方法以及使用demo 本资源是利用java的jedis实现

    redisTemplate封装成redisUtils和分布式锁实现

    以下是一个简单的分布式锁实现: ```java public class DistributedLock { private static final String LOCK_PREFIX = "lock:"; public boolean lock(String lockKey, long waitTime, long leaseTime) { ...

    用Redis实现分布式锁_redis_分布式_

    二、Redis分布式锁实现 1. 锁的创建:通常使用`SETNX`命令尝试设置一个键(如`lock_key`),如果键不存在,则设置成功,表示获取到锁。同时,为了防止死锁,可以设置一个过期时间,如`EXPIRE lock_key timeout`,...

    AOP方式实现的redis分布式锁

    redis分布式锁的实现: 1、利用LUA脚本,防止redis意外导致死锁。 2、基于AOP方式实现。 3、只需要在方法上声明@DistributedLock(可以是controller的方法也可以是service的公共方法)即可实现锁功能。 4、支持...

    基于 Redis 的分布式锁

    分布式锁是分布式系统中用于同步资源访问的一种机制,它能够保证在分布式部署的应用系统中,同一时刻只允许一个客户端对共享...在实际应用中,需要根据具体业务场景和需求,权衡利弊,选择最适合的分布式锁实现方案。

    基于Redis的分布式锁的实现方案.pdf

    基于Redis的分布式锁的实现方案 本文讨论了分布式锁的实现方案,主要基于Redis实现分布式锁,以解决分布式系统中资源访问的同步问题。在分布式系统中,需要协调各个系统或主机之间的资源访问,以避免彼此干扰和保证...

    解析分布式锁之redis实现1

    分布式锁是一种在分布式系统中确保多个节点对共享资源进行互斥访问的机制...在实际应用中,要充分理解业务需求,根据场景选择合适的分布式锁实现方式,同时确保异常处理和降级策略,以保证系统的稳定性和数据的一致性。

    Redission分布式锁-本地单机Redis实战-springboot-redis-lock.zip

    本项目“Redission分布式锁-本地单机Redis实战-springboot-redis-lock”旨在教你如何在SpringBoot项目中集成Redisson库,实现基于Redis的分布式锁功能。下面我们将深入探讨相关的知识点。 1. **Redisson**:...

Global site tag (gtag.js) - Google Analytics