redisson作为分布式锁能够解决分布式的加锁解锁问题,还能够实现锁的设置存活时间以及自动续期。
1、引入依赖
org.redisson redisson 3.12.5
2、创建redisson配置类实现注入
package com.atguigu.gulimall.product.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyRedisConfig {
// @Value("${ipAddr}")
// private String ipAddr;
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson() {
Config config = new Config();
// 创建单例模式的配置
// config.useSingleServer().setAddress("redis://" + ipAddr + ":6379");
config.useSingleServer().setAddress("redis://192.168.116.170:6379");
return Redisson.create(config);
}
}
3、测试,能输出结果则说明成功
import org.junit.Test;
import org.junit.runner.RunWith;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class GulimallProductApplicationTests {
@Autowired
StringRedisTemplate stringRedisTemplate;
@Autowired
RedissonClient redissonClient;
@Test
public void redistest() {
System.out.println(redissonClient);
}
}
lock
@Test
public void redistest(){
RLock lock = redissonClient.getLock("mylock");//获取锁
// lock.lock();//加锁
lock.lock(10, TimeUnit.SECONDS);//加锁,设置解锁时间
/**
* lock有两种方法 一种是空参 另一种是带参
* 空参方法:会默认调用看门狗的过期时间30*1000(30秒)
* 然后在正常运行的时候,会启用定时任务调用重置时间的方法(间隔为开门看配置的默认过期时间的三分之一,也就是10秒)
* 当出现错误的时候就会停止续期,直到到期释放锁或手动释放锁
* 带参方法:手动设置解锁时间,到期后自动解锁,或者业务完成后手动解锁,不会自动续期
*/
try{
System.out.println("加锁成功,开始执行业务");
Thread.sleep(5000);
}catch (Exception e){
}finally {
lock.unlock();
}
}
trylock
@Test
public void redistest(){
RLock lock = redissonClient.getLock("mylock");//获取锁
try {
lock.tryLock(20,10, TimeUnit.SECONDS);//加锁,设置等待时间,设置解锁时间
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* trylock可以设置等待解锁时间,如果是lock的话,会进入阻塞式等待,直到解锁
* 而trylock方法可以设置等待时间,这里设置了20秒。如果超过20秒则不等待了,取消访问
*/
try{
System.out.println("加锁成功,开始执行业务");
Thread.sleep(20000);
}catch (Exception e){
}finally {
lock.unlock();
}
}
fair lock
@Test
public void redistest(){
RLock fairLock = redissonClient.getFairLock("mylock");//获取锁公平锁
fairLock.lock();
/**
* FairLock是公平锁,如果不采取公平锁,当一个锁被释放后,所有的线程又开始抢占锁
* 如果采取公平锁,当一个锁被释放后,会按照先后顺序优先让先发起请求的线程抢占锁
*/
try{
System.out.println("加锁成功,开始执行业务");
Thread.sleep(20000);
}catch (Exception e){
}finally {
fairLock.unlock();
}
}
redlock
@Test
public void redistest(){
RLock lock1 = redissonClient.getLock("lock1");
RLock lock2 = redissonClient.getLock("lock2");
RLock lock3 = redissonClient.getLock("lock3");
RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// 同时加锁:lock1 lock2 lock3
// 红锁在大部分节点上加锁成功就算成功。
lock.lock();
try{
System.out.println("加锁成功,开始执行业务");
Thread.sleep(20000);
}catch (Exception e){
}finally {
lock.unlock();
}
}
redissonMultiLock
@Test
public void redistest(){
RLock lock1 = redissonClient.getLock("lock1");
RLock lock2 = redissonClient.getLock("lock2");
RLock lock3 = redissonClient.getLock("lock3");
RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3);
// 同时加锁:lock1 lock2 lock3
// 所有的锁都上锁成功才算成功。
lock.lock();
try{
System.out.println("加锁成功,开始执行业务");
Thread.sleep(20000);
}catch (Exception e){
}finally {
lock.unlock();
}
}
读写锁(可以保证读到的都是最新的数据,如果在读的同时有写锁存在,则会等待直到写操作完成,然后读取最新的数据)只要有写的存在,都必须等待释放锁。读+读无需等待,redis里会记录下所有的读锁,但是不会限制阻塞。
@ResponseBody
@RequestMapping("/write")
public String write() {
String s =" ";
RReadWriteLock lock = redissonClient.getReadWriteLock("rw-lock");
//添加写锁,写锁是排他锁,当锁住之后,其他线程都要等待,以此保证读到的是最新的数据
RLock rLock = lock.writeLock();
rLock.lock();
try{
s = UUID.randomUUID().toString();
Thread.sleep(30000);
stringRedisTemplate.opsForValue().set("writeValue",s);
} catch (InterruptedException e) {
}finally {
rLock.unlock();
}
return s;
}
@ResponseBody
@RequestMapping("/read")
public String read() {
String s =" ";
RReadWriteLock lock = redissonClient.getReadWriteLock("rw-lock");
RLock rLock = lock.readLock();
rLock.lock();
try{
s = stringRedisTemplate.opsForValue().get("writeValue");
} catch (Exception e) {
}finally {
rLock.unlock();
}
return s;
}
闭锁
设置一个闭锁,设置需要通过的数量,只有当通过的数量达到设定的数量,才解锁,否则会一直等待
/**
* 闭锁 只有设定的人全通过才关门
*/
@ResponseBody
@GetMapping("/index/lockDoor")
public String lockDoor() throws InterruptedException {
RCountDownLatch door = redissonClient.getCountDownLatch("door");
// 设置这里有5个人
door.trySetCount(5);
door.await();
return "5个人全部通过了...";
}
@ResponseBody
@GetMapping("/index/go/{id}")
public String go(@PathVariable("id") Long id) throws InterruptedException {
RCountDownLatch door = redissonClient.getCountDownLatch("door");
// 每访问一次相当于出去一个人,当访问五次的时候解锁
door.countDown();
return id + "走了";
}
信号量
需要现在redis数据库存入一个信号量,假设存入的信号量为park value为3 表示有三个车位,当调用第一个代码时,获取车位,信号量减一,变成2,当信号量为0时,如果调用该方法,则进入阻塞,直到执行第二串代码,释放value
/**
* 尝试获取车位 [信号量]
* 信号量:也可以用作限流
*/
@ResponseBody
@GetMapping("/index/park")
public String park() {
RSemaphore park = redissonClient.getSemaphore("park");
boolean acquire = park.tryAcquire();
return "获取车位 =>" + acquire;
}
/**
* 尝试获取车位
*/
@ResponseBody
@GetMapping("/index/go/park")
public String goPark() {
RSemaphore park = redissonClient.getSemaphore("park");
park.release();
return "ok => 车位+1";
}