数据库
首页 > 数据库> > redis分布式锁

redis分布式锁

作者:互联网

package lock;

//加锁设置的参数
public class LockParam {
	
  
//锁的key
  private String lockKey;
  //尝试获得锁的时间(单位:毫秒),默认值:3000毫秒
  private Long tryLockTime;
  //尝试获得锁后,持有锁的时间(单位:毫秒),默认值:5000毫秒
  private Long holdLockTime;
  
  public String getLockKey() {
		return lockKey;
	}
	public void setLockKey(String lockKey) {
		this.lockKey = lockKey;
	}
	public Long getTryLockTime() {
		return tryLockTime;
	}
	public void setTryLockTime(Long tryLockTime) {
		this.tryLockTime = tryLockTime;
	}
	public Long getHoldLockTime() {
		return holdLockTime;
	}
	public void setHoldLockTime(Long holdLockTime) {
		this.holdLockTime = holdLockTime;
	}

  public LockParam(String lockKey){
      this(lockKey,1000*3L,1000*5L);
  };
  public LockParam(String lockKey,Long tryLockTime){
      this(lockKey,tryLockTime,1000*5L);
  };
  public LockParam(String lockKey,Long tryLockTime,Long holdLockTime){
      this.lockKey = lockKey;
      this.tryLockTime = tryLockTime;
      this.holdLockTime = holdLockTime;
  };
}

  //redis分布式锁实现

package lock;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;

import java.util.Collections;
import java.util.UUID;

/**
 * redis分布式锁
 */
@Slf4j
public class RedisLock {

    //锁key的前缀
    private final static String prefix_key = "redisLock:";
    //释放锁的lua脚本
    private final static  String unLockScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    //执行unLockScript脚本,释放锁成功值
    private final static  Long unLockSuccess = 1L;
    //加锁设置的参数(key值、超时时间、持有锁的时间)
    private LockParam lockParam;
    //尝试获得锁的截止时间【lockParam.getTryLockTime()+System.currentTimeMillis()】
    private Long tryLockEndTime;
    //redis加锁的key
    private String redisLockKey;
    //redis加锁的vlaus
    private String redisLockValue;
    //redis加锁的成功标示
    private Boolean holdLockSuccess= Boolean.FALSE;


    //jedis实例
    private Jedis jedis;
    //获取jedis实例
    private Jedis getJedis(){
        return this.jedis;
    }
    //关闭jedis
    private void closeJedis(Jedis jedis){
        jedis.close();
        jedis = null;
    }

    public RedisLock(LockParam lockParam){
        if(lockParam==null){
            new RuntimeException("lockParam is null");
        }
        if(lockParam.getLockKey()==null || lockParam.getLockKey().trim().length()==0){
            new RuntimeException("lockParam lockKey is error");
        }
        this.lockParam = lockParam;

        this.tryLockEndTime = lockParam.getTryLockTime()+System.currentTimeMillis();
        this.redisLockKey = prefix_key.concat(lockParam.getLockKey());
        this.redisLockValue = UUID.randomUUID().toString().replaceAll("-","");

        //todo 到时候可以更换获取Jedis实例的实现
        jedis = new Jedis("127.0.0.1",6379);
    }

    /**
     * 加锁
     * @return 成功返回true,失败返回false
     */
    public boolean lock() {
        while(true){
            //判断是否超过了,尝试获取锁的时间
            if(System.currentTimeMillis()>tryLockEndTime){
                return false;
            }
            //尝试获取锁
            holdLockSuccess = tryLock();
            if(Boolean.TRUE.equals(holdLockSuccess)){
                return true;//获取锁成功
            }

            try {
                //获得锁失败,休眠50毫秒再去尝试获得锁,避免一直请求redis,导致redis cpu飙升
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 执行一次加锁操作:成功返回true 失败返回false
     * @return 成功返回true,失败返回false
     */
    private boolean tryLock() {
        try {
            String result = getJedis().set(redisLockKey,redisLockValue, "NX", "PX", lockParam.getHoldLockTime());
            if ("OK".equals(result)) {
                return true;
            }
        }catch (Exception e){
        	e.printStackTrace();
            //log.warn("tryLock failure redisLockKey:{} redisLockValue:{} lockParam:{}",redisLockKey,redisLockValue,lockParam,e);
        }
        return false;
    }

    /**
     * 解锁
     * @return 成功返回true,失败返回false
     */
    public Boolean unlock() {
        Object result = null;
        try {
            //获得锁成功,才执行lua脚本
            if(Boolean.TRUE.equals(holdLockSuccess)){
                //执行Lua脚本
                result = getJedis().eval(unLockScript, Collections.singletonList(redisLockKey), Collections.singletonList(redisLockValue));
                if (unLockSuccess.equals(result)) {//释放成功
                    return true;
                }
            }
        } catch (Exception e) {
        	e.printStackTrace();
            //log.warn("unlock failure redisLockKey:{} redisLockValue:{} lockParam:{} result:{}",redisLockKey,redisLockValue,lockParam,result,e);
        } finally {
            this.closeJedis(jedis);
        }
        return false;
    }
}

  //测试类

package lock;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class test {
    static String lockKey = "66688";
    public static void main(String[] args) throws InterruptedException {
    	System.out.println();
        System.out.println("下面测试两个线程同时,抢占锁的结果");
        Thread thread1 = new Thread(()->{
            testRedisLock();
        });
        thread1.setName("我是线程1");
        Thread thread2 = new Thread(()->{
            testRedisLock();
        });
        thread2.setName("我是线程2");

        //同时启动线程
        thread1.start();
        thread2.start();

        Thread.sleep(1000*20);
        System.out.println("-----------------我是一条分割线----------------");
        System.out.println("");
        System.out.println("");
        System.out.println("");


        System.out.println("下面是测试  一个线程获取锁成功后,由于业务执行时间超过了设置持有锁的时间,是否会把其他线程持有的锁给释放掉");
        Thread thread3 = new Thread(()->{
            testRedisLock2();
        });
        thread3.setName("我是线程3");
        thread3.start();

        Thread.sleep(1000*1);//暂停一秒是为了让线程3获的到锁
        Thread thread4 = new Thread(()->{
            testRedisLock();
        });
        thread4.setName("我是线程4");
        thread4.start();
    }

    public static void testRedisLock(){
        LockParam lockParam = new LockParam(lockKey);
        lockParam.setTryLockTime(2000L);//2秒时间尝试获得锁
        lockParam.setHoldLockTime(1000*10L);//获得锁成功后持有锁10秒时间
        RedisLock redisLock = new RedisLock(lockParam);
        try {
            Boolean lockFlag = redisLock.lock();
            System.out.println("加锁结果:{}"+lockFlag);
            if(lockFlag){
                try {
                    //20秒模拟处理业务代码时间
                    Thread.sleep(1000*5L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }catch (Exception e) {
            System.out.println("testRedisLock e---->"+e);
        }finally {
            boolean unlockResp = redisLock.unlock();
            System.out.println("释放锁结果:{}"+unlockResp);
        }
    }


    public static void testRedisLock2(){
        LockParam lockParam = new LockParam(lockKey);
        lockParam.setTryLockTime(1000*2L);//2秒时间尝试获得锁
        lockParam.setHoldLockTime(1000*2L);//获得锁成功后持有锁2秒时间
        RedisLock redisLock = new RedisLock(lockParam);
        try {
            Boolean lockFlag = redisLock.lock();
            System.out.println("加锁结果:{}"+lockFlag);
            if(lockFlag){
                try {
                    //10秒模拟处理业务代码时间
                    Thread.sleep(1000*10L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }catch (Exception e) {
            System.out.println("testRedisLock e---->"+e);
        }finally {
            boolean unlockResp = redisLock.unlock();
            System.out.println("释放锁结果:{}"+unlockResp);
        }
    }
}

  //pom.xml文件

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.cn</groupId>
  <artifactId>redisLock</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  
  <dependencies>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.11.5</version>
        </dependency>
        <!--  -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.3</version>
        </dependency>
         <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <optional>true</optional>
        </dependency>
  </dependencies>
     
  <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

  

标签:return,redis,System,private,lockKey,lockParam,public,分布式
来源: https://www.cnblogs.com/xianz666/p/15498816.html