redis分布式锁之可重入锁的实现代码

上篇redis实现的分布式锁,有一个问题,它不可重入。

所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞。 同一个人拿一个锁 ,只能拿一次不能同时拿2次。

1、什么是可重入锁?它有什么作用?

可重入锁,也叫做递归锁,指的是在同一线程内,外层函数获得锁之后,内层递归函数仍然可以获取到该锁。 说白了就是同一个线程再次进入同样代码时,可以再次拿到该锁。 它的作用是:防止在同一线程中多次获取锁而导致死锁发生。

2、那么java中谁实现了可重入锁了?

在java的编程中synchronized 和 ReentrantLock都是可重入锁。我们可以参考ReentrantLock的代码

3、基于ReentrantLock的可重入锁

ReentrantLock,是一个可重入且独占式的锁,是一种递归无阻塞的同步锁。

3.1、看个ReentrantLock的例子

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class ReentrantLockDemo {
    //锁
    private static ReentrantLock lock =  new ReentrantLock();
    public void doSomething(int n){
        try{
            //进入递归第一件事:加锁
            lock.lock();
            log.info("--------lock()执行后,getState()的值:{} lock.isLocked():{}",lock.getHoldCount(),lock.isLocked());
            log.info("--------递归{}次--------",n);
            if(n<=2){
                this.doSomething(++n);
            }else{
                return;
            }
        }finally {
            lock.unlock();
            log.info("--------unlock()执行后,getState()的值:{} lock.isLocked():{}",lock.getHoldCount(),lock.isLocked());
        }
    }

    public static void main(String[] args) {
        ReentrantLockDemo reentrantLockDemo=new ReentrantLockDemo();
        reentrantLockDemo.doSomething(1);
        log.info("执行完doSomething方法 是否还持有锁:{}",lock.isLocked());
    }

}

3.2、执行结果

16:35:58.051 [main] INFO com.test.ReentrantLockDemo - --------lock()执行后,getState()的值:1 lock.isLocked():true
16:35:58.055 [main] INFO com.test.ReentrantLockDemo - --------递归1次--------
16:35:58.055 [main] INFO com.test.ReentrantLockDemo - --------lock()执行后,getState()的值:2 lock.isLocked():true
16:35:58.055 [main] INFO com.test.ReentrantLockDemo - --------递归2次--------
16:35:58.055 [main] INFO com.test.ReentrantLockDemo - --------lock()执行后,getState()的值:3 lock.isLocked():true
16:35:58.055 [main] INFO com.test.ReentrantLockDemo - --------递归3次--------
16:35:58.055 [main] INFO com.test.ReentrantLockDemo - --------unlock()执行后,getState()的值:2 lock.isLocked():true
16:35:58.055 [main] INFO com.test.ReentrantLockDemo - --------unlock()执行后,getState()的值:1 lock.isLocked():true
16:35:58.055 [main] INFO com.test.ReentrantLockDemo - --------unlock()执行后,getState()的值:0 lock.isLocked():false
16:35:58.055 [main] INFO com.test.ReentrantLockDemo - 执行完doSomething方法 是否还持有锁:false

3.3、 从上面栗子可以看出ReentrantLock是可重入锁,那么他是如何实现的了,我们看下源码就知道了

 final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            //先判断,c(state)是否等于0,如果等于0,说明没有线程持有锁
            if (c == 0) {
                //通过cas方法把state的值0替换成1,替换成功说明加锁成功
                if (compareAndSetState(0, acquires)) {
                    //如果加锁成功,设置持有锁的线程是当前线程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {//判断当前持有锁的线程是否是当前线程
                //如果是当前线程,则state值加acquires,代表了当前线程加锁了多少次
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

ReentrantLock的加锁流程是:
1,先判断是否有线程持有锁,没有加锁进行加锁
2、如果加锁成功,则设置持有锁的线程是当前线程
3、如果有线程持有了锁,则再去判断,是否是当前线程持有了锁
4、如果是当前线程持有锁,则加锁数量(state)+1

/**
         * 释放锁
         * @param releases
         * @return
         */
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;//state-1 减加锁次数
            //如果持有锁的线程,不是当前线程,抛出异常
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();

            boolean free = false;
            if (c == 0) {//如果c==0了说明当前线程,已经要释放锁了
                free = true;
                setExclusiveOwnerThread(null);//设置当前持有锁的线程为null
            }
            setState(c);//设置c的值
            return free;
        }

看ReentrantLock的解锁代码我们知道,每次释放锁的时候都对state减1,
当c值等于0的时候,说明锁重入次数也为0了,
最终设置当前持有锁的线程为null,state也设置为0,锁就释放了。

4、那么redis要怎么实现可重入的操作了?

看ReentrantLock的源码我们知道,它是加锁成功了,记录了当前持有锁的线程,并通过一个int类型的数字,来记录了加锁次数。

我们知道ReentrantLock的实现原理了,那么redis只要下面两个问题解决,就能实现重入锁了:
1、怎么保存当前持有的线程
2、加锁次数(重入了多少次),怎么记录维护

4.1、第一个问题:怎么保存当前持有的线程

1.上一篇文章我们用的是redis 的set命令存的是string类型,他能保存当前持有的线程吗?
valus值我们可以保存当前线程的id来解决。
2. 但是集群环境下我们线程id可能是重复了那怎么解决?
项目在启动的生成一个全局进程id,使用进程id+线程id 那就是唯一的了

4.2、第二个问题:加锁次数(重入了多少次),怎么记录维护

他能记录下来加锁次数吗?
如果valus值存的格式是:系进程id+线程id+加锁次数,那可以实现

存没问题了,但是重入次数要怎么维护了, 它肯定要保证原子性的,能解决吗?
好像用java代码或者lua脚本都没法解决,因为都是实现都需要两步来维护这个重入次数的

  • 第一步:先获取到valus值,把取到加锁次数+1
  • 第二部:把新的值再设置进去
  • 在执行第二步操作之前,如果这个key失效了(设置持有锁超时了),如果还能再设置进去,就会有并发问题了

5、我们已经知道SET是不支持重入锁的,但我们需要重入锁,怎么办呢?

目前对于redis的重入锁业界还是有很多解决方案的,最流行的就是采用Redisson。

6、什么是 Redisson?

Redisson是Redis官方推荐的Java版的Redis客户端。 它基于Java实用工具包中常用接口,为使用者提供了一系列具有分布式特性的常用工具类。 它在网络通信上是基于NIO的Netty框架,保证网络通信的高性能。 在分布式锁的功能上,它提供了一系列的分布式锁;如:可重入锁(Reentrant Lock)、公平锁(Fair Lock、联锁(MultiLock)、 红锁(RedLock)、 读写锁(ReadWriteLock)等等。

Redisson github地址

7、Redisson的分布锁如何使用

引入依赖包

<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.15.5</version>
</dependency>  

代码

import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;

@Slf4j
public class ReentrantLockDemo1 {
    //锁
    public static RLock lock;

    static {
        //Redisson需要的配置
        Config config = new Config();
        String node = "127.0.0.1:6379";//redis地址
        node = node.startsWith("redis://") ? node : "redis://" + node;
        SingleServerConfig serverConfig = config.useSingleServer()
                .setAddress(node)
                .setTimeout(3000)//超时时间
                .setConnectionPoolSize(10)
                .setConnectionMinimumIdleSize(10);
        //serverConfig.setPassword("123456");//设置redis密码
        // 创建RedissonClient客户端实例
        RedissonClient redissonClient = Redisson.create(config);
        //创建redisson的分布式锁
        RLock rLock = redissonClient.getLock("666");
        lock = rLock;
    }
    public void doSomething(int n){
        try{
            //进入递归第一件事:加锁
            lock.lock();
            log.info("--------lock()执行后,getState()的值:{} lock.isLocked():{}",lock.getHoldCount(),lock.isLocked());
            log.info("--------递归{}次--------",n);
            if(n<=2){
                this.doSomething(++n);
            }else{
                return;
            }
        }finally {
            lock.unlock();
            log.info("--------unlock()执行后,getState()的值:{} lock.isLocked():{}",lock.getHoldCount(),lock.isLocked());
        }
    }
    public static void test(){
        log.info("--------------start---------------");
        ReentrantLockDemo1 reentrantLockDemo=new ReentrantLockDemo1();
        reentrantLockDemo.doSomething(1);
        log.info("执行完doSomething方法 是否还持有锁:{}",ReentrantLockDemo1.lock.isLocked());
        log.info("--------------end---------------");
    }
    public static void main(String[] args) {
        test();
    }
}

执行结果

2021-05-23 22:49:01.322 INFO 69041 --- [nio-9090-exec-1] org.redisson.Version : Redisson 3.15.5
2021-05-23 22:49:01.363 INFO 69041 --- [sson-netty-5-22] o.r.c.pool.MasterConnectionPool : 10 connections initialized for /127.0.0.1:6379
2021-05-23 22:49:01.363 INFO 69041 --- [sson-netty-5-23] o.r.c.pool.MasterPubSubConnectionPool : 1 connections initialized for /127.0.0.1:6379
2021-05-23 22:49:01.367 INFO 69041 --- [nio-9090-exec-1] com.test.ReentrantLockDemo1 : --------------start---------------
2021-05-23 22:49:01.435 INFO 69041 --- [nio-9090-exec-1] com.test.ReentrantLockDemo1 : --------lock()执行后,getState()的值:1 lock.isLocked():true
2021-05-23 22:49:01.436 INFO 69041 --- [nio-9090-exec-1] com.test.ReentrantLockDemo1 : --------递归1次--------
2021-05-23 22:49:01.442 INFO 69041 --- [nio-9090-exec-1] com.test.ReentrantLockDemo1 : --------lock()执行后,getState()的值:2 lock.isLocked():true
2021-05-23 22:49:01.442 INFO 69041 --- [nio-9090-exec-1] com.test.ReentrantLockDemo1 : --------递归2次--------
2021-05-23 22:49:01.448 INFO 69041 --- [nio-9090-exec-1] com.test.ReentrantLockDemo1 : --------lock()执行后,getState()的值:3 lock.isLocked():true
2021-05-23 22:49:01.448 INFO 69041 --- [nio-9090-exec-1] com.test.ReentrantLockDemo1 : --------递归3次--------
2021-05-23 22:49:01.456 INFO 69041 --- [nio-9090-exec-1] com.test.ReentrantLockDemo1 : --------unlock()执行后,getState()的值:2 lock.isLocked():true
2021-05-23 22:49:01.461 INFO 69041 --- [nio-9090-exec-1] com.test.ReentrantLockDemo1 : --------unlock()执行后,getState()的值:1 lock.isLocked():true
2021-05-23 22:49:01.465 INFO 69041 --- [nio-9090-exec-1] com.test.ReentrantLockDemo1 : --------unlock()执行后,getState()的值:0 lock.isLocked():false
2021-05-23 22:49:01.467 INFO 69041 --- [nio-9090-exec-1] com.test.ReentrantLockDemo1 : 执行完doSomething方法 是否还持有锁:false
2021-05-23 22:49:01.467 INFO 69041 --- [nio-9090-exec-1] com.test.ReentrantLockDemo1 : --------------end---------------

看控制台打印能清楚知道Redisson是支持可重入锁了。

8、那么Redisson是如何实现的了?

我们跟一下lock.lock()的代码,发现它最终调用的是org.redisson.RedissonLock#tryLockInnerAsync的方法,具体如下:

 <T> RFuture<T> tryLockInnerAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {
        return evalWriteAsync(getRawName(), LongCodec.INSTANCE, command,
                "if (redis.call('exists', KEYS[1]) == 0) then " +
                        "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
                        "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                        "return nil; " +
                        "end; " +
                        "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +
                        "redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
                        "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                        "return nil; " +
                        "end; " +
                        "return redis.call('pttl', KEYS[1]);",
                Collections.singletonList(getRawName()), unit.toMillis(leaseTime), getLockName(threadId));
    }

8.1、上面的代码,用到的redis命令先梳理一下

exists 查询一个key是否存在

EXISTS key [key ...]
返回值
如下的整数结果
1 如果key存在
0 如果key不存在

hincrby :将hash中指定域的值增加给定的数字

pexpire:设置key的有效时间以毫秒为单位

hexists:判断field是否存在于hash中

pttl:获取key的有效毫秒数

8.2、看lua脚本传入的参数我们知道:

  • KEYS[1] = key的值
  • ARGV[1]) = 持有锁的时间
  • ARGV[2] = getLockName(threadId) 下面id就算系统在启动的时候会全局生成的uuid 来作为当前进程的id,加上线程id就是getLockName(threadId)了,可以理解为:进程ID+系统ID = ARGV[2]
protected String getLockName(long threadId) {
        return id + ":" + threadId;
    }

8.3、代码截图

从截图上可以看到,它是使用lua脚本来保证多个命令执行的原子性,使用了hash来实现了分布式锁
现在我们来看下lua脚本的加锁流程

8.4、第一个if判断

  • 204行:它是先判断了当前key是否存在,从EXISTS命令我们知道返回值是0说明key不存在,说明没有加锁
  • 205行:hincrby命令是对 ARGV[2] = 进程ID+系统ID 进行原子自增加1
  • 206行:是对整个hash设置过期期间

8.5、下面来看第二个if判断

  • 209行:判断field是否存在于hash中,如果存在返回1,返回1说明是当前进程+当前线程ID 之前已经获得到锁了
  • 210行:hincrby命令是对 ARGV[2] = 进程ID+系统ID 进行原子自增加1,说明重入次数加1了
  • 211行:再对整个hash设置过期期间

8.6、下图是redis可视化工具看到是如何在hash存储的结构

Redisson的整个加锁流程跟ReentrantLock的加锁逻辑基本相同

8.7、解锁代码位于 org.redisson.RedissonLock#unlockInnerAsync,如下:

 return evalWriteAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
                "if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +
                        "return nil;" +
                        "end; " +
                        "local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +
                        "if (counter > 0) then " +
                        "redis.call('pexpire', KEYS[1], ARGV[2]); " +
                        "return 0; " +
                        "else " +
                        "redis.call('del', KEYS[1]); " +
                        "redis.call('publish', KEYS[2], ARGV[1]); " +
                        "return 1; " +
                        "end; " +
                        "return nil;",
                Arrays.asList(getRawName(), getChannelName()), LockPubSub.UNLOCK_MESSAGE, internalLockLeaseTime, getLockName(threadId));
    }

看这个解锁的Lua脚本,流程跟Reentrantlock的解锁逻辑也基本相同没啥好说的了。

以上就是redis分布式锁-可重入锁的详细内容,更多关于redis分布式锁的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringBoot集成Redisson实现分布式锁的方法示例

    上篇 <SpringBoot 集成 redis 分布式锁优化>对死锁的问题进行了优化,今天介绍的是 redis 官方推荐使用的 Redisson ,Redisson 架设在 redis 基础上的 Java 驻内存数据网格(In-Memory Data Grid),基于NIO的 Netty 框架上,利用了 redis 键值数据库.功能非常强大,解决了很多分布式架构中的问题. Github的wiki地址: https://github.com/redisson/redisson/wiki 官方文档

  • Redis Template实现分布式锁的实例代码

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁. 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 1.互斥性.在任意时刻,只有一个客户端能持有锁. 2.不会发生死锁.即使有一个

  • 浅谈Redis分布式锁的正确实现方式

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁. 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 1.互斥性.在任意时刻,只有一个客户端能持有锁. 2.不会发生死锁.即使有一个

  • Redis实现分布式锁的几种方法总结

    Redis实现分布式锁的几种方法总结 分布式锁是控制分布式系统之间同步访问共享资源的一种方式.在分布式系统中,常常需要协调他们的动作.如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁. 我们来假设一个最简单的秒杀场景:数据库里有一张表,column分别是商品ID,和商品ID对应的库存量,秒杀成功就将此商品库存量-1.现在假设有1000个线程来秒杀两件商品,500个线程秒杀第一个商品,

  • SpringBoot使用Redisson实现分布式锁(秒杀系统)

    前面讲完了Redis的分布式锁的实现,接下来讲Redisson的分布式锁的实现,一般提及到Redis的分布式锁我们更多的使用的是Redisson的分布式锁,Redis的官方也是建议我们这样去做的.Redisson点我可以直接跳转到Redisson的官方文档. 1.1.引入Maven依赖 <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter&l

  • redis中使用java脚本实现分布式锁

    redis被大量用在分布式的环境中,自然而然分布式环境下的锁如何解决,立马成为一个问题.例如我们当前的手游项目,服务器端是按业务模块划分服务器的,有应用服,战斗服等,但是这两个vm都有可能同时改变玩家的属性,这如果在同一个vm下面,就很容易加锁,但如果在分布式环境下就没那么容易了,当然利用redis现有的功能也有解决办法,比如redis的脚本. redis在2.6以后的版本中增加了Lua脚本的功能,可以通过eval命令,直接在RedisServer环境中执行Lua脚本,并且可以在Lua脚本中调用

  • Redis分布式锁的实现方式(redis面试题)

    什么是分布式锁? 要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁.进程锁. 线程锁:主要用来给方法.代码块加锁.当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段.线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synchronized是共享对象头,显示锁Lock是共享某个变量(state). 进程锁:为了控制同一操作系统中多个进程访问某个共享资源,因为进程具有独立性,各个进程无法访问其他进程的资源,因此无法通过synchronize

  • springboot+redis分布式锁实现模拟抢单

    本篇内容主要讲解的是redis分布式锁,这个在各大厂面试几乎都是必备的,下面结合模拟抢单的场景来使用她:本篇不涉及到的redis环境搭建,快速搭建个人测试环境,这里建议使用docker:本篇内容节点如下: jedis的nx生成锁 如何删除锁 模拟抢单动作(10w个人开抢) jedis的nx生成锁 对于java中想操作redis,好的方式是使用jedis,首先pom中引入依赖: <dependency> <groupId>redis.clients</groupId> &

  • 基于redis分布式锁实现秒杀功能

    最近在项目中遇到了类似"秒杀"的业务场景,在本篇博客中,我将用一个非常简单的demo,阐述实现所谓"秒杀"的基本思路. 业务场景 所谓秒杀,从业务角度看,是短时间内多个用户"争抢"资源,这里的资源在大部分秒杀场景里是商品:将业务抽象,技术角度看,秒杀就是多个线程对资源进行操作,所以实现秒杀,就必须控制线程对资源的争抢,既要保证高效并发,也要保证操作的正确. 一些可能的实现 刚才提到过,实现秒杀的关键点是控制线程对资源的争抢,根据基本的线程知识,可

  • 一篇文章让你彻底了解Java可重入锁和不可重入锁

    可重入锁 广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁. 我的理解就是,某个线程已经获得某个锁,可以无需等待而再次获取锁,并且不会出现死锁(不同线程当然不能多次获得锁,需要等待). 简单的说,就是某个线程获得某个锁,之后可以不用等待而再次获取锁且不会出现死锁. 常见的可重入锁 Synchronized和ReentrantLock 都是可重入锁. 可重入锁的释放 同一个线程获取同一个锁,

  • redis分布式锁之可重入锁的实现代码

    上篇redis实现的分布式锁,有一个问题,它不可重入. 所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞. 同一个人拿一个锁 ,只能拿一次不能同时拿2次. 1.什么是可重入锁?它有什么作用? 可重入锁,也叫做递归锁,指的是在同一线程内,外层函数获得锁之后,内层递归函数仍然可以获取到该锁. 说白了就是同一个线程再次进入同样代码时,可以再次拿到该锁. 它的作用是:防止在同一线程中多次获取锁而导致死锁发生. 2.那么java中谁实现了可重入锁了?

  • Java锁之可重入锁介绍

    锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchronized 和 ReentrantLock等等 ) .这些已经写好提供的锁为我们开发提供了便利,但是锁的具体性质以及类型却很少被提及.本系列文章将分析JAVA下常见的锁名称以及特性,为大家答疑解惑. 四.可重入锁: 本文里面讲的是广义上的可重入锁,而不是单指JAVA下的ReentrantLock. 可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响. 在JAV

  • java高并发的ReentrantLock重入锁

    目录 synchronized的局限性 ReentrantLock ReentrantLock基本使用 ReentrantLock是可重入锁 ReentrantLock实现公平锁 ReentrantLock获取锁的过程是可中断的 tryLock无参方法 tryLock有参方法 ReentrantLock其他常用的方法 获取锁的4种方法对比 总结 synchronized的局限性 synchronized是java内置的关键字,它提供了一种独占的加锁方式.synchronized的获取和释放锁由j

  • Java可重入锁的实现原理与应用场景

    可重入锁,从字面来理解,就是可以重复进入的锁. 可重入锁,也叫做递归锁,指的是同一线程外层函数获得锁之后,内层递归函数仍然有获取该锁的代码,但不受影响. 在JAVA环境下ReentrantLock和synchronized都是可重入锁. synchronized是一个可重入锁.在一个类中,如果synchronized方法1调用了synchronized方法2,方法2是可以正常执行的,这说明synchronized是可重入锁.否则,在执行方法2想获取锁的时候,该锁已经在执行方法1时获取了,那么方法

  • Springboot基于Redisson实现Redis分布式可重入锁源码解析

    目录 一.前言 二.为什么使用Redisson 1.我们打开官网 2.我们可以看到官方让我们去使用其他 3.打开官方推荐 4.找到文档 三.Springboot整合Redisson 1.导入依赖 2.以官网为例查看如何配置 3.编写配置类 4.官网测试加锁例子 5.根据官网简单Controller接口编写 6.测试 四.lock.lock()源码分析 1.打开RedissonLock实现类 2.找到实现方法 3.按住Ctrl进去lock方法 4.进去尝试获取锁方法 5.查看tryLockInne

  • Golang实现可重入锁的示例代码

    目录 什么是可重入锁 具体实现 项目中遇到了可重入锁的需求和实现,具体记录下. 什么是可重入锁 我们平时说的分布式锁,一般指的是在不同服务器上的多个线程中,只有一个线程能抢到一个锁,从而执行一个任务.而我们使用锁就是保证一个任务只能由一个线程来完成.所以我们一般是使用这样的三段式逻辑: Lock();DoJob();Unlock(); 但是由于我们的系统都是分布式的,这个锁一般不会只放在某个进程中,我们会借用第三方存储,比如 Redis 来做这种分布式锁.但是一旦借助了第三方存储,我们就必须面对

  • Java并发编程之重入锁与读写锁

    重入锁 重入锁,顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁.重进入是指任意线程在获取到锁之后能够再次获取该锁而不会被锁阻塞,该特性的实现需要解决以下两个问题. 1.线程再次获取锁.锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次成功获取. 2.锁的最终释放.线程重复n次获取了锁,随后在第n次释放该锁后,其他线程能够获取到该锁.锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于0时表示锁已经成功释放

  • 举例讲解Python中的死锁、可重入锁和互斥锁

    一.死锁 简单来说,死锁是一个资源被多次调用,而多次调用方都未能释放该资源就会造成死锁,这里结合例子说明下两种常见的死锁情况. 1.迭代死锁 该情况是一个线程"迭代"请求同一个资源,直接就会造成死锁: import threading import time class MyThread(threading.Thread): def run(self): global num time.sleep(1) if mutex.acquire(1): num = num+1 msg = se

  • Python多线程编程(六):可重入锁RLock

    考虑这种情况:如果一个线程遇到锁嵌套的情况该怎么办,这个嵌套是指当我一个线程在获取临界资源时,又需要再次获取. 根据这种情况,代码如下: 复制代码 代码如下: ''' Created on 2012-9-8   @author: walfred @module: thread.ThreadTest6 '''    import threading  import time    counter = 0  mutex = threading.Lock()    class MyThread(thr

随机推荐