原创

Redission

温馨提示:
本文最后更新于 2022年10月27日,已超过 918 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

官方文档 https://github.com/redisson/redisson

一 加入redission依赖

<!-- https://mvnrepository.com/artifact/org.redisson/redisson -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.16.8</version>
</dependency>

二 配置

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 MyRedissonConfig {


    @Bean(destroyMethod="shutdown")
    public RedissonClient redission(){

        Config config = new Config();
        //报错This instance has cluster support disabled 此实例已禁用群集支持,采用下面单节点配置方式
        config.useClusterServers()

                //可以用"rediss://"来启用SSL连接
                .addNodeAddress("redis://127.0.0.1:6379");
        RedissonClient redisson = Redisson.create(config);
        return redisson;
    }
}
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 MyRedissonConfig {


    @Bean(destroyMethod="shutdown")
    public RedissonClient redission(){

        Config config = new Config();
        config.useSingleServer().setAddress("redis://192.168.101.164:6379");
//        config.useClusterServers()
                //可以用"rediss://"来启用SSL连接
//                .addNodeAddress("redis://127.0.0.1:6379");
        RedissonClient redisson = Redisson.create(config);
        return redisson;
    }

三 分布式锁

获取分布式锁,进行加锁(加锁过程是一个阻塞过程,没有获取到锁的线程会一直等待到获取锁)。加锁成功后执行业务代码,最后再释放锁 。

@GetMapping("/hello")
    public R hello(){
        //1获取锁
        RLock lock = redissonClient.getLock("my-lock");
        //2手动加锁
        lock.lock();
//        lock.lock(10,TimeUnit.SECONDS);
        //3执行业务代码
        try {
            System.out.println("加锁成功,正在执行业务代码。。。。"+Thread.currentThread().getId());
            TimeUnit.SECONDS.sleep(10);
//            Thread.sleep(30000);
        }catch (Exception e){

        }finally {
            //4释放锁
            System.out.println("释放锁成功");
            lock.unlock();
        }
        return R.ok().put("data","测试成功");
    }

1.直接加锁

lock.lock();该方法默认超时时间为30s,有看门狗给锁自动续过期时间(1/3超时时间续期一次)。当服务停止 导致不能释放锁。看门狗则不会再自动续期时间。

2. 超时加锁

lock.lock(10,TimeUnit.SECONDS); 在指定时间内获取锁,如果获取不到锁,则不再等待获取锁。

加锁底层源码:

    private <T> RFuture<Long> tryAcquireAsync(long leaseTime, TimeUnit unit, long threadId) {
        //leaseTime设置的等待时间,如果设置了,直接走加锁流程。
        if (leaseTime != -1) {
            return tryLockInnerAsync(leaseTime, unit, threadId, RedisCommands.EVAL_LONG);
        }
        //否则进入以下代码,看门狗自动续过期时间
        RFuture<Long> ttlRemainingFuture = tryLockInnerAsync(commandExecutor.getConnectionManager().getCfg().getLockWatchdogTimeout(), TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);
        ttlRemainingFuture.onComplete((ttlRemaining, e) -> {
            if (e != null) {
                return;
            }

            // lock acquired
            if (ttlRemaining == null) {
                scheduleExpirationRenewal(threadId);
            }
        });
        return ttlRemainingFuture;
    }

四 读写锁

四种模式

读+读 相当于没有加锁

读+写 读写操作互不影响

写+读 读操作只能等写操作完成才能获取锁

写+写 写操作阻塞,其他的写操作只能等前一个写操作完成才能获取锁

    @ResponseBody
    @GetMapping("/read")
    public String readLock(){
        //1获取读取锁
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("rw-lock");
        //2 获取读锁
        RLock rLock = readWriteLock.readLock();
        //3加锁
        rLock.lock();
        String val = "";
        try {
           val  = redisUtil.getKey("uuid");

        }catch (Exception e){

        }finally {
            //4释放锁
            rLock.unlock();
        }
        return val;
    }
    @ResponseBody
    @GetMapping("/write")
    public String writeLock(){
        //1获取读取锁
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("rw-lock");
        //2 获取写锁
        RLock rLock = readWriteLock.writeLock();
        //3加锁
        rLock.lock();
        String val = "";
        try {
            val  = UUID.randomUUID().toString();
            redisUtil.setKey("uuid",val);
            TimeUnit.SECONDS.sleep(10);
        }catch (Exception e){

        }finally {
            //4释放锁
            rLock.unlock();
        }
        return val;
    }

五 信号量

给信号量对应的锁设置值(信号量值),然后才能使用信号量。当信号量打满后,其他线程只能等待获取。或者获取失败后返回对应的信息

park.tryAcquire();//获取锁,返回truefalse
park.acquire();//获取锁,阻塞,一直等待
    /**
     * remark:信号量测试
     * 信号量原本值有才能占用成功
     * tryAcquire尝试获取信号量,成功返回true  失败返回false 可以用于限流
     */
    @ResponseBody
    @GetMapping("/park")
    public String park(){
        RSemaphore park = redissonClient.getSemaphore("park");
        boolean b = park.tryAcquire();
        try {
//            park.acquire();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "停车成功";
    }

    @ResponseBody
    @GetMapping("/gogo")
    public String gogo(){
        RSemaphore park = redissonClient.getSemaphore("park");
        try {
            park.release();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "离场成功";
    }

六 闭锁

等待执行达到指定数量时,再执行。

    /**
     * remark:
     * 闭锁(CountDownLatch)
     * 等待所有线程执行完毕再执行
     *
     */
    @ResponseBody
    @GetMapping("/close")
    public String close() throws InterruptedException {
        RCountDownLatch countDownLatch = redissonClient.getCountDownLatch("holiday-clock");
        countDownLatch.trySetCount(5L);
        countDownLatch.await();

        return "保安关门成功,学校放假了。。。。。。";
    }

    @ResponseBody
    @GetMapping("/goHome/{id}")
    public String goHome(@PathVariable Long id) throws InterruptedException {
        RCountDownLatch countDownLatch = redissonClient.getCountDownLatch("holiday-clock");
        countDownLatch.countDown();
        return id+"班放学了。。。。。";
    }
正文到此结束