原理:

原子性:利用setnx实现。SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。时间复杂度O(1);

预防死锁:利用expire实现,超时通过redis的机制删除;

谁锁谁有权限解:传入一个value(随机生成),只要持有者才能释放掉锁(即del掉该key)

源码:

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

@Component
public class RedisService {
    private Logger logger = LoggerFactory.getLogger(RedisService.class);

    @Value("${spring.redis.database}")
    private int dataBase;

    @Autowired
    private JedisPool jedisPool;

    private final static String LOCK_KEY = "Distributed_";

    /**
     * 分布式锁,尝试获取锁
     *
     * @param scene          场景字段,不为空
     * @param myId           线程标识,不为空
     * @param maxLockSeconds 最大锁定时间,秒,大于0
     * @return
     */
    public Boolean tryLock(String scene, String myId, int maxLockSeconds) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            String key = LOCK_KEY + scene;
            Long nxResult = jedis.setnx(key, myId);
            if (nxResult.equals(1L)) {
                jedis.expire(key, maxLockSeconds);
                return true;
            }
        } catch (Exception e) {
            logger.error("tryLock exception", e);
        } finally {
            returnResource(jedis);
        }
        logger.error("分布式锁,尝试获取锁-失败");
        return false;
    }

    /**
     * 分布式锁,释放锁
     *
     * @param scene 场景字段,不为空
     * @param myId  线程标识,不为空
     * @return
     */
    public Boolean unLock(String scene, String myId) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            String key = LOCK_KEY + scene;
            String value = jedis.get(key);
            if (StringUtils.isNotEmpty(value) && value.equals(myId)) {
                //哪个线程锁的,哪个线程解
                return jedis.del(key).equals(1L);
            }
        } catch (Exception e) {
            logger.error("unLock exception", e);
        } finally {
            returnResource(jedis);
        }
        logger.error("分布式锁,释放锁-失败");
        return false;
    }

    private Jedis getJedis() {
        Jedis jedis = jedisPool.getResource();
        jedis.select(dataBase);
        return jedis;
    }

    private void returnResource(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }

}

测试代码:

import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@SpringBootTest
@RunWith(SpringRunner.class)
public class RedisServiceTest extends TestCase {

    private static final Logger logger = LoggerFactory.getLogger(RedisServiceTest.class);

    @Resource
    private RedisService redisService;

    @Test
    public void distributedLockTest() throws InterruptedException {
        String myId = MD5Util.textToMD5L16(System.currentTimeMillis() + "");
        String scene = "distributedLockTest";
        Boolean lockResult = redisService.tryLock(scene, myId, 10);
        if (lockResult) {
            Thread.sleep(3000);//do some thing
            Boolean unLockResult = redisService.unLock(scene, myId);
            logger.error("释放锁:{}", unLockResult);
        }
    }
}

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐