背景

基于redis实现。

代码

package xxx.trade.util;import xxx.core.exception.BizException;import org.apache.commons.lang.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import redis.clients.jedis.JedisCluster;import java.util.Collections;public class JedisUtil {    private static final Logger LOGGER = LoggerFactory            .getLogger(JedisUtil.class);    private static JedisCluster jedisCluster;    private static final String PREFIX="xxx-callback:";    public JedisUtil() {        // do nothing    }    public static boolean lock(String key , String value , String nxx, Long lockExpireTimeOut) {        if (StringUtils.isBlank(key)) {            throw new BizException("key must not null!");        } else {            LOGGER.info("JedisTemplate:get cache key={},value={}", key, value);            String result = jedisCluster.set(PREFIX+key ,value,nxx,"EX",lockExpireTimeOut);            if ("OK".equals(result)) {                return true;            }            return false;        }    }    public static boolean unlock(String key, String value) {        try {            String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";            Object result = jedisCluster.eval(luaScript, Collections.singletonList(PREFIX + key),                    Collections.singletonList(value));            if (!"0".equals(result.toString())) {                return true;            }        } catch (Exception ex) {            LOGGER.error("unlock error");        }        return false;    }        static {        ApplicationContext context = new ClassPathXmlApplicationContext(new String[]                {"conf/springconf/redis/redis-spring-context.xml"});        jedisCluster = (JedisCluster)context.getBean("jedisClusterConfigA");    }}

应用

次要是两步
1.获取锁
2.开释锁


代码

try{  获取锁;  解决业务;} finally{  开释锁;}

外围

是基于redis的set命令。

超时

为什么要设置超时?因为怕断电这种状况,导致获取锁之后,始终没有开释,导致其余的服务都获取不了锁。

断电之后,开释锁的代码,就没执行。

lua

为什么要用Lua,因为是lua脚本原子操作。

而删除的时候,蕴含两步
1.先读 //先测验redis是否有数据
2.后写 //如果没有,就删除数据

所以,开释锁的代码应用了lua脚本来确保两步操作的原子性。