Redis客户端Redisson+SpringBoot实现的分布式锁案例

1.Redisson介绍wiki:https://github.com/redisson/redisson/wiki/

2.整合Spingboot实现分布式锁:

   application.properties配置redis地址:

redisson.address=redis://*.*.*.*:6379
redisson.password=123456

  Redisson相关配置及工具类:

package com.demo.distributedlock.redis;

import org.springframework.boot.context.properties.ConfigurationProperties;
/**
 * @author libo
 * @ClassName RedissonProperties
 * @Description: RedissonPropertis配置
 * @date 2018/11/16 16:55
 */
@ConfigurationProperties(prefix="redisson")
public class RedissonProperties {
    private int timeout = 3000;

    private String address;

    private String password;

    private int connectionPoolSize = 64;

    private int connectionMinimumIdleSize=10;

    private int slaveConnectionPoolSize = 250;

    private int masterConnectionPoolSize = 250;

    private String[] sentinelAddresses;

    private String masterName;

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public int getSlaveConnectionPoolSize() {
        return slaveConnectionPoolSize;
    }

    public void setSlaveConnectionPoolSize(int slaveConnectionPoolSize) {
        this.slaveConnectionPoolSize = slaveConnectionPoolSize;
    }

    public int getMasterConnectionPoolSize() {
        return masterConnectionPoolSize;
    }

    public void setMasterConnectionPoolSize(int masterConnectionPoolSize) {
        this.masterConnectionPoolSize = masterConnectionPoolSize;
    }

    public String[] getSentinelAddresses() {
        return sentinelAddresses;
    }

    public void setSentinelAddresses(String sentinelAddresses) {
        this.sentinelAddresses = sentinelAddresses.split(",");
    }

    public String getMasterName() {
        return masterName;
    }

    public void setMasterName(String masterName) {
        this.masterName = masterName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getConnectionPoolSize() {
        return connectionPoolSize;
    }

    public void setConnectionPoolSize(int connectionPoolSize) {
        this.connectionPoolSize = connectionPoolSize;
    }

    public int getConnectionMinimumIdleSize() {
        return connectionMinimumIdleSize;
    }

    public void setConnectionMinimumIdleSize(int connectionMinimumIdleSize) {
        this.connectionMinimumIdleSize = connectionMinimumIdleSize;
    }

}
package com.demo.distributedlock.redis;

import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author libo
 * @ClassName RedissonAutoConfiguration
 * @date 2018/11/16 17:25
 */
@Configuration
@ConditionalOnClass(Config.class)
@EnableConfigurationProperties(RedissonProperties.class)
public class RedissonAutoConfiguration {

    @Autowired
    private RedissonProperties redissonProperties;

    /***
     * @Author libo
     * @Description //单机模式自动装配
     * @return
     */
    @Bean
    @ConditionalOnProperty(name = "redisson.address")
    RedissonClient redissonSingle(){
        Config config = new Config();
        SingleServerConfig serverConfig = config.useSingleServer()
                .setAddress(redissonProperties.getAddress())
                .setTimeout(redissonProperties.getTimeout())
                .setConnectionPoolSize(redissonProperties.getConnectionPoolSize())
                .setConnectionMinimumIdleSize(redissonProperties.getConnectionMinimumIdleSize());
        if(StringUtils.isNotBlank(redissonProperties.getPassword())) {
            serverConfig.setPassword(redissonProperties.getPassword());
        }
        return Redisson.create(config);
    }

    /**
     * 装配locker类,并将实例注入到RedissonLockUtil中
     * @return
     */
    @Bean
    RedissLockUtil redissLockUtil(RedissonClient redissonClient){
        RedissLockUtil redissLockUtil = new RedissLockUtil();
        redissLockUtil.setRedissonClient(redissonClient);
        return  redissLockUtil;
    }


}
package com.demo.distributedlock.redis;

import java.util.concurrent.TimeUnit;

import org.redisson.api.*;

/**
 * @author libo
 * @ClassName RedissLockUtil
 * @Description: redisson 分布式锁工具类
 * @date 2018/11/16 17:06
 */
public class RedissLockUtil {

    private static RedissonClient redissonClient;

    public void setRedissonClient(RedissonClient redissonClient){
        this.redissonClient = redissonClient;
    }

    /***
     * @Author libo
     * @Description //加锁
     * @return org.redisson.api.RLock
     */
    public static RLock getLock(String lockKey){
        RLock lock = redissonClient.getLock(lockKey);
        return  lock;
    }
    
    /***
     * @Author libo
     * @Description //获取公平锁
     * @return org.redisson.api.RLock
     */
    public static RLock getFairLock(String lockKey){
        RLock fairLock = redissonClient.getFairLock(lockKey);
        return  fairLock;
    }
    /***
     * @Author libo
     * @Description //获取读写锁
     * @return org.redisson.api.RReadWriteLock
     */
    public static RReadWriteLock getReadWriteLock(String lockKey){
        RReadWriteLock rwlock = redissonClient.getReadWriteLock(lockKey);
        return rwlock;
    }
    /***
     * @Author libo
     * @Description //获取信号量
     * @return
     */
    public static RSemaphore getSemaphore(String lockKey){
        RSemaphore semaphore = redissonClient.getSemaphore(lockKey);
        return semaphore;
    }

    /***
     * @Author libo
     * @Description //获取countDownLatch
     * @return
     */
    public static RCountDownLatch  getCountDownLatch(String lockKey){
        RCountDownLatch  rCountDownLatch  = redissonClient.getCountDownLatch(lockKey);
        return rCountDownLatch;
    }

    /***
     * @Author libo
     * @Description //异步加锁
     * @Date 15:03 2018/12/18
     * @return org.redisson.api.RFuture
     */
    public static RFuture tryLockAsync(String lockKey,int waitTime,int leaseTime,TimeUnit timeUnit) throws InterruptedException {
        RLock lock = redissonClient.getLock(lockKey);
        Thread.sleep(1000);
        return lock.tryLockAsync(waitTime,leaseTime,timeUnit);
    }

    /***
     * @Author libo
     * @Description //释放锁
     * @Date 17:12 2018/11/16
     * @return void
     */
    public static void unLock(String lockKey){
        RLock lock = redissonClient.getLock(lockKey);
        lock.unlock();
    }

    /***
     * @Author libo
     * @Description //释放锁
     * @Date 17:12 2018/11/16
     * @return void
     */
    public static void unLock(RLock lock){
        lock.unlock();
    }

    /***
     * @Author libo
     * @Description //带超时的锁   单位 秒
     * @Date 17:17 2018/11/16
     * @return org.redisson.api.RLock
     */
    public static RLock lock(String lockKey,int timeout){
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, TimeUnit.SECONDS);
        return lock;
    }

    public static RLock lock(String lockKey,TimeUnit timeUnit,int timeout){
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, timeUnit);
        return lock;
    }

    /***
     * @Author libo
     * @param lockKey
     * @param waitTime 最多等待时间
     * @param leaseTime 上锁后自动释放锁时间
     * @Date 17:20 2018/11/16
     * @return boolean
     */
    public static boolean tryLock(String lockKey,int waitTime, int leaseTime){
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return  lock.tryLock(waitTime,leaseTime,TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            return  false;
        }
    }

    /***
     * @Author libo
     * @param lockKey
     * @param waitTime 最多等待时间
     * @param leaseTime 上锁后自动释放锁时间
     * @Date 17:20 2018/11/16
     * @return boolean
     */
    public static boolean tryLock(String lockKey,TimeUnit timeUnit, int waitTime, int leaseTime){
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return  lock.tryLock(waitTime,leaseTime,timeUnit);
        } catch (InterruptedException e) {
            return  false;
        }
    }
}

分布式锁测试测试类:

package com.example.demo;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.redisson.RedissonMultiLock;
import org.redisson.RedissonRedLock;
import org.redisson.api.*;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import com.demo.seckill.Application;
import com.demo.seckill.distributedlock.redis.RedissLockUtil;
/**
 * @author libo
 * @ClassName RedissonLockDemo
 * @Description: 分布式锁demo
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class,webEnvironment = SpringBootTest.WebEnvironment.NONE)
@WebAppConfiguration
public class RedissonLockDemo {

    /***
     * @Author libo
     * @Description // Redisson可重入锁测试,实现了java对象的lock接口
     * @return
     */
    @Test
    public void testReentrantLock() throws InterruptedException {
        RLock lock =  RedissLockUtil.getLock("lockKey");
        for (int i=0;i<3;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // 1. 最常见的使用方法
                    // lock.lock();
                    // 2. 支持过期解锁功能,10秒钟以后自动解锁, 无需调用unlock方法手动解锁
                    // lock.lock(10, TimeUnit.SECONDS);
                    // 3. 尝试加锁,最多等待3秒,上锁以后10秒自动解锁
                    try {
                        boolean res = lock.tryLock(3, 10, TimeUnit.SECONDS);
                        if(res){
                            System.out.println(Thread.currentThread().getName()+"线程获取锁成功");
                            //获得锁,执行业务
                        }else {
                            System.out.println(Thread.currentThread().getName()+"线程获取锁失败");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
        //过期自动解锁,无需手动解锁
        //lock.unlock();
        Thread.sleep(10000);
    }
    /***
     * @Author libo
     * @Description // 为分布式锁提供异步执行的方法
     * @return void
     */
    @Test
    public void testAsyncReentrantLock() throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    /*lock.tryLockAsync();
                    //加锁10后自动解锁
                    lock.tryLockAsync(10, TimeUnit.SECONDS);
                    lock.tryLockAsync(3, 20, TimeUnit.SECONDS)*/
                    RFuture   res  = RedissLockUtil.tryLockAsync("getLock",3, 20, TimeUnit.SECONDS);
                    if(res.get()){
                        System.out.println("这个是获取到锁之后,异步调用的方法");
                    }
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
        System.out.println("这是主线程的方法");
        Thread.sleep(10000);
    }

    /**
     * 公平锁(Fair Lock)
     * Redisson分布式可重入公平锁也是实现了java.util.concurrent.locks.Lock接口的一种RLock对象。
     * 在提供了自动过期解锁功能的同时,保证了当多个Redisson客户端线程同时请求加锁时,优先分配给先发出请求的线程。
     * @param redisson
     */

    @Test
    public void testFairLock() throws InterruptedException {
        RLock fairLock = RedissLockUtil.getFairLock("getLock");
        new Thread(new MyRunner("线程A",fairLock)).start();
        new Thread(new MyRunner("线程B",fairLock)).start();
        Thread.sleep(10000);
    }

    /**
     * 联锁(MultiLock)
     * Redisson的RedissonMultiLock对象可以将多个RLock对象关联为一个联锁,
     * 每个RLock对象实例可以来自于不同的Redisson实例
     */
    @Test
    public void testMultiLock(){
        RLock lock1 = RedissLockUtil.getLock("lock1");
        RLock lock2 = RedissLockUtil.getLock("lock2");
        RLock lock3 = RedissLockUtil.getLock("lock3");
        RedissonMultiLock multiLock = new RedissonMultiLock(lock1,lock2,lock3);
        try{
            //multiLock.lock();
            //multiLock.lock(100,TimeUnit.SECONDS);
            boolean res = multiLock.tryLock(10, 10, TimeUnit.SECONDS);
            if(res){
                System.out.println("这是联锁测试");
            }
        }catch (Exception e){
            System.out.println("获取不到锁,发生异常");
            e.printStackTrace();
        }finally {
            try{
                multiLock.unlock();
            }catch (Exception e){
                System.out.println("获取不到锁,解锁发生异常");
            }
        }
    }

    @Test
    public void testAlwaysLock() throws InterruptedException {
        RLock lock =  RedissLockUtil.getLock("lock1");
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 1. 最常见的使用方法
                // lock.lock();
                // 2. 支持过期解锁功能,10秒钟以后自动解锁, 无需调用unlock方法手动解锁
                // lock.lock(10, TimeUnit.SECONDS);
                // 3. 尝试加锁,最多等待3秒,上锁以后10秒自动解锁
                try {
                    boolean res = lock.tryLock();
                    if(res){
                        System.out.println(Thread.currentThread().getName()+"线程获取锁成功");
                        //获得锁,执行业务
                    }else {
                        System.out.println(Thread.currentThread().getName()+"线程获取锁失败");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
        Thread.sleep(1000000);
    }
    /**
     *  红锁(RedLock)
     *  Redisson的RedissonRedLock对象实现了Redlock介绍的加锁算法。
     *  该对象也可以用来将多个RLock对象关联为一个红锁,每个RLock对象实例可以来自于不同的Redisson实例
     */
    @Test
    public void testRedLock(){
        RLock lock1 = RedissLockUtil.getLock("lock1");
        RLock lock2 = RedissLockUtil.getLock("lock2");
        RLock lock3 = RedissLockUtil.getLock("lock3");
        RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
        try {
            // 同时加锁:lock1 lock2 lock3, 红锁在大部分节点上加锁成功就算成功。
            lock.lock();
            // 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
            boolean res = lock.tryLock(10, 10, TimeUnit.SECONDS);
            if (res) {
                System.out.println("这是红锁测试");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /***
     * @Author libo
     * @Description //读写锁测试
     * @return
     */
    @Test
    public void testRWlock() throws InterruptedException {
        RReadWriteLock rwlock = RedissLockUtil.getReadWriteLock("lockKey");
        for (int i = 0; i < 3; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        boolean redRes = rwlock.readLock().tryLock(5, 10, TimeUnit.SECONDS);
                        if(redRes){
                            System.out.println(Thread.currentThread().getName()+"线程获取读锁成功");
                        }else{
                            System.out.println(Thread.currentThread().getName()+"线程获取读锁失败");
                        }
                        boolean writeRes = rwlock.writeLock().tryLock(10, 10, TimeUnit.SECONDS);
                        if (writeRes){
                            System.out.println(Thread.currentThread().getName()+"线程获取写锁成功");
                        }else {
                            System.out.println(Thread.currentThread().getName()+"线程获取写锁失败");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
        Thread.sleep(100000);
    }

    /***
     * @Author libo
     * @Description //信号量测试
     * @return
     */
    @Test
    public void testSemaphore() throws InterruptedException {
        RSemaphore semaphore = RedissLockUtil.getSemaphore("semaphore ");
        semaphore.trySetPermits(10);
        Driver driver = new Driver(semaphore);
        for (int i = 0; i < 5; i++) {
            (new Car(driver)).start();
        }
        Thread.sleep(10000);
    }

    /***
     * @Author libo
     * @Description //RCountDownLatch测试
     * @return
     */
    @Test
    public void testCountDownLatch() throws InterruptedException {
        RCountDownLatch countDownlatch = RedissLockUtil.getCountDownLatch("countDownlatch ");
        countDownlatch.trySetCount(5);
        Driver driver = new Driver(countDownlatch);
        for (int i = 0; i < 5; i++) {
            (new Car(driver)).start();
        }
        System.out.println("主线程阻塞,等待所有子线程执行完成");
        //countDownlatch.await()使得主线程阻塞直到countDownlatch.countDown()为零才继续执行
        countDownlatch.await();
        System.out.println("所有线程执行完成!");
        Thread.sleep(10000);
    }
    class  MyRunner implements Runnable{
        String threadName;
        RLock rLock;

        public MyRunner(String threadName,RLock rLock){
            this.threadName = threadName;
            this.rLock = rLock;
        }

        public String getThreadName() {
            return threadName;
        }

        public void setThreadName(String threadName) {
            this.threadName = threadName;
        }

        public RLock getrLock() {
            return rLock;
        }

        public void setrLock(RLock rLock) {
            this.rLock = rLock;
        }
        @Override
        public void run() {
            try{
                /*
                fairLock.lock();
                // 支持过期解锁功能, 10秒钟以后自动解锁,无需调用unlock方法手动解锁
                fairLock.lock(10, TimeUnit.SECONDS);*/
                // 尝试加锁,最多等待100秒,上锁以后10秒自动解锁
                boolean res = rLock.tryLock(100, 10, TimeUnit.SECONDS);
                if (res) {
                    System.out.println("线程名称:"+getThreadName());
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

     class Driver {
        private RSemaphore semaphore;
        private RCountDownLatch rCountDownLatch;

        public Driver(RSemaphore semaphore){
            this.semaphore = semaphore;
        }
        public Driver(RCountDownLatch rCountDownLatch){
            this.rCountDownLatch = rCountDownLatch;
        }
        public void driveCar() {
            try {
                // 从信号量中获取一个允许机会
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());
                // 释放允许,将占有的信号量归还
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
         public void driveCar2() {
             System.out.println( Thread.currentThread().getName() +" start at "+ System.currentTimeMillis());
             // 每个独立子线程执行完后,countDownLatch值减1
             rCountDownLatch.countDown();
         }
    }
    class Car extends Thread{
        private Driver driver;

        public Car(Driver driver) {
            super();
            this.driver = driver;
        }

        public void run() {
            //driver.driveCar();
            driver.driveCar2();
        }
    }
}

 

你可能感兴趣的:(redis,java,分布式锁,Spring,Boot)