文章
问答
冒泡
redisson实现分布式锁

随着微服务的推广,现在越来越多的有一定体量的项目,都开始微服务化。

微服务的优点,不必赘述。但是,凡是都是有两面的,比如,分布式的并发安全性。在单应用中,我们可以通过加锁的方式去实现。那么在分布式项目中,我们同样是遵循加锁的思路。

redisson作为一个redis客户端,自身就有分布式锁的功能。

1.在spring boot项目中配置redisson

1.1添加依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.11.4</version>
</dependency>
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.11.4</version>
</dependency>

1.2配置RedissonClient

通过 redisson-spring-boot-starter 源码可见,这里使用的RedisTemplate 就是srping-data-redis的RedisTemplate。所以,我们需要先配置spring redis.

spring:
  redis:
    host: 127.0.0.1
    port: 6379

这样,一个单机服务就可以跑起来了。不过,redisson还有其他配置,这些配置是独立于redis的,需要单独去配置。

在org.redisson.spring.starter.RedissonProperties 这个类中,可以看到

@ConfigurationProperties(prefix = "spring.redis.redisson")
public class RedissonProperties {

    private String config;

    public String getConfig() {
        return config;
    }

    public void setConfig(String config) {
        this.config = config;
    }
        
}

可见,这里的config 一个配置文件地址,所以,我们可以这么配置

application.yaml

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    redisson:
      config: "classpath:redisson.yaml"

redisson.yaml

singleServerConfig:
  address: "127.0.0.1:6379"
  password: null
  clientName: null
  database: 7 #选择使用哪个数据库0~15
  idleConnectionTimeout: 10000
  pingTimeout: 1000
  connectTimeout: 10000
  timeout: 3000
  retryAttempts: 3
  retryInterval: 1500
  reconnectionTimeout: 3000
  failedAttempts: 3
  subscriptionsPerConnection: 5
  subscriptionConnectionMinimumIdleSize: 1
  subscriptionConnectionPoolSize: 50
  connectionMinimumIdleSize: 32
  connectionPoolSize: 64
  dnsMonitoringInterval: 5000
  #dnsMonitoring: false

threads: 0
nettyThreads: 0
codec:
  class: "org.redisson.codec.JsonJacksonCodec"
transportMode: "NIO"

注意,这里的配置文件里key 要用驼峰写法,不能用中横线

2.使用redisson

2.1redisson支持的锁,基本有如下几种:

  • 可重入锁(Reentrant Lock)
  • 公平锁(Fair Lock)
  • 联锁(MultiLock)
  • 红锁(RedLock)
  • 读写锁(ReadWriteLock)

可重入锁:是最基本的锁,一旦上锁,其他的应用在未获得锁的时候,不能读也不能写

@Test
public void lock(){
    RLock rLock = redissonClient.getLock("lock");
    try {
       // rLock.lock(30, TimeUnit.SECONDS);
        rLock.tryLock(3,100, TimeUnit.SECONDS);
        System.out.println("get lock1");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally {
        rLock.unlock();
    }
}

lock 中的两个参数 第一个是锁的保持时间,超过这个时间,锁会自动释放,第二个是单位。如果第一个参数是-1 ,则必须等到执行锁释放,其他的操作才能拿到这个锁。

tryLock 第一参数是尝试时间,超过则放弃,后面两个参数与lock一样。

公平锁: 保证了当多个Redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程

@Test
public void fairLock(){
    RLock fairLock = redissonClient.getFairLock("lock");
    try{
        fairLock.lock(10, TimeUnit.SECONDS);
        System.out.println("get fair lock");
    }finally {
        fairLock.unlock();
    }
}

联锁:可以将多个RLock对象关联为一个联锁,每个RLock对象实例可以来自于不同的Redisson实例

我没有多个redisson实例,就网上找了个

public void testMultiLock(RedissonClient redisson1,RedissonClient redisson2, RedissonClient redisson3){
	RLock lock1 = redisson1.getLock("lock1");
	RLock lock2 = redisson2.getLock("lock2");
	RLock lock3 = redisson3.getLock("lock3");
	RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
	try {
		// 同时加锁:lock1 lock2 lock3, 所有的锁都上锁成功才算成功。
		lock.lock();
		// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
		boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
	} catch (InterruptedException e) {
		e.printStackTrace();
	} finally {
		lock.unlock();
	}
}

红锁:实现了Redlock介绍的加锁算法

这个也是网上抄的

public void testRedLock(RedissonClient redisson1,RedissonClient redisson2, RedissonClient redisson3){
	RLock lock1 = redisson1.getLock("lock1");
	RLock lock2 = redisson2.getLock("lock2");
	RLock lock3 = redisson3.getLock("lock3");
	RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
	try {
		// 同时加锁:lock1 lock2 lock3, 红锁在大部分节点上加锁成功就算成功。
		lock.lock();
		// 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
		boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
	} catch (InterruptedException e) {
		e.printStackTrace();
	} finally {
		lock.unlock();
	}
}

读写锁:读锁和写锁,互不干扰

@Test
public void lockWriteLock(){
    RReadWriteLock rLock = redissonClient.getReadWriteLock("lock");
    try {
        rLock.writeLock().lock(30, TimeUnit.SECONDS);
      //  rLock.writeLock().lock();
        System.out.println("get write lock");
        Thread.sleep(100000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally {
        rLock.writeLock().unlock();
    }

}

@Test
public void lockWriteLock2(){
    RReadWriteLock rLock = redissonClient.getReadWriteLock("lock");
    rLock.writeLock().lock(30, TimeUnit.SECONDS);
    System.out.println("get write lock2");
    rLock.writeLock().unlock();
}

@Test
public void lockRead(){
    RReadWriteLock rLock = redissonClient.getReadWriteLock("lock");
    rLock.readLock().lock(30, TimeUnit.SECONDS);
    System.out.println("get read lock");
    rLock.readLock().unlock();
}


参考文档:

https://blog.csdn.net/l1028386804/article/details/73523810

https://github.com/redisson/redisson

spring boot
redis
redisson
分布式锁

关于作者

落雁沙
非典型码农
获得点赞
文章被阅读