美文网首页
redis单机版分布式锁

redis单机版分布式锁

作者: 快点给我想个名 | 来源:发表于2019-01-22 10:00 被阅读0次
package com.simon.lock.redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.Collections;

/**
 * @Author: lim
 * @Description: redis分布式锁
 * @Date: 2018/11/22.
 */
public class RedisLockUtil {

    private static JedisPool jedisPool;

    static {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(20);
        config.setMaxIdle(10);
        config.setMinIdle(2);
        config.setTestOnBorrow(true);
        config.setTestOnReturn(true);
        //连接消耗完毕后,是否阻塞。false抛异常,true等待直到超时,默认超时
        config.setBlockWhenExhausted(false);
        jedisPool = new JedisPool(config,"127.0.0.1",6379,1000);
    }


    /**
     * 在 Redis 2.6.12 版本以前, SET 命令总是返回 OK 。
     * 从 Redis 2.6.12 版本开始, SET 在设置操作成功完成时,才返回 OK
     */
    private static final String LOCK_SUCCESS = "OK";


    private static final String RELEASE_SUCCESS = "1";

    /**
     * 从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改:
     * EX second :设置键的过期时间为 second 秒。
     * PX millisecond :设置键的过期时间为 millisecond 毫秒。
     * NX :只在键不存在时,才对键进行设置操作。
     * XX :只在键已经存在时,才对键进行设置操作。
     */
    private static final String PX = "PX";
    private static final String NX = "NX";


    /**
     * 获取锁
     * @param lockName 锁名称
     * @param identityID 自身标识
     * @param getTimeout 获取锁超时时间
     * @param expireTime 锁超时时间
     * @return
     */
    public boolean tryLock(String lockName,String identityID,Long getTimeout,Long expireTime){

        Jedis jedis = jedisPool.getResource();
        //获取锁超时时间
        Long end = System.currentTimeMillis() + getTimeout;

        try {
            while (System.currentTimeMillis() < end){

                //开始获取锁
                String result = jedis.set(lockName, identityID, NX, PX, expireTime);

                if(LOCK_SUCCESS.equals(result)){
                    return true;
                }

                Thread.sleep(10);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            jedis.close();
        }

        return false;
    }


    /**
     * 释放锁
     * @param lockName 锁标识
     * @param identityID 自身标识
     * @return
     * 实现一个针对某个手机号的访问频次, 以下是lua脚本,保存为phone_limit.lua
     * local num=redis.call('incr',KEYS[1])
     * if tonumber(num)==1 then redis.call('expire',KEYS[1],ARGV[1])
     *      return 1
     * elseif tonumber(num)>tonumber(ARGV[2]) then
     *      return 0
     * else
     *      return 1
     * end
     */
    public boolean releaseLock(String lockName,String identityID){

        Jedis jedis = jedisPool.getResource();

        try {
            String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
            Object result = jedis.eval(script, Collections.singletonList(lockName), Collections.singletonList(identityID));

            if(RELEASE_SUCCESS.equals(result.toString())){
                return true;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            jedis.close();
        }

        return false;
    }



}

测试

package com.simon;

/**
 * @Author: lim
 * @Description:
 * @Date: 2018/11/22.
 */

public class RedisLockTest {


    private static final String lockName = "LOCKNAME";
    private static int counter = 10;

    public static void main(String[] args) {

        Service s = new Service(counter,lockName);

        for(int i = 0;i < 10;i++){
            Thread t = new Thread(s);
            t.start();
        }
    }

}

相关文章

网友评论

      本文标题:redis单机版分布式锁

      本文链接:https://www.haomeiwen.com/subject/ectljqtx.html