在同一個jvm進程中時,能夠使用JUC提供的一些鎖來解決多個線程競爭同一個共享資源時候的線程安全問題,可是當多個不一樣機器上的不一樣jvm進程共同競爭同一個共享資源時候,juc包的鎖就無能無力了,這時候就須要分佈式鎖了。常見的有使用zk的最小版本,redis的set函數,數據庫鎖來實現,本節咱們談談Redis單實例狀況下使用set函數來實現分佈式鎖。java
首先咱們來具體看代碼:redis
package com.jiaduo.DistributedLock; import java.util.Collections; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; public class DistributedLock { private static final String LOCK_SUCCESS = "OK"; private static final String SET_IF_NOT_EXIST = "NX"; private static final String SET_WITH_EXPIRE_TIME = "PX"; private static final Long RELEASE_SUCCESS = 1L; private static void validParam(JedisPool jedisPool, String lockKey, String requestId, int expireTime) { if (null == jedisPool) { throw new IllegalArgumentException("jedisPool obj is null"); } if (null == lockKey || "".equals(lockKey)) { throw new IllegalArgumentException("lock key is blank"); } if (null == requestId || "".equals(requestId)) { throw new IllegalArgumentException("requestId is blank"); } if (expireTime < 0) { throw new IllegalArgumentException("expireTime is not allowed less zero"); } } /** * * @param jedis * @param lockKey * @param requestId * @param expireTime * @return */ public static boolean tryLock(JedisPool jedisPool, String lockKey, String requestId, int expireTime) { validParam(jedisPool, lockKey, requestId, expireTime); Jedis jedis = null; try { jedis = jedisPool.getResource(); String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if (LOCK_SUCCESS.equals(result)) { return true; } } catch (Exception e) { throw e; } finally { if (null != jedis) { jedis.close(); } } return false; } /** * * @param jedis * @param lockKey * @param requestId * @param expireTime */ public static void lock(JedisPool jedisPool, String lockKey, String requestId, int expireTime) { validParam(jedisPool, lockKey, requestId, expireTime); while (true) { if (tryLock(jedisPool, lockKey, requestId, expireTime)) { return; } } } /** * * @param jedis * @param lockKey * @param requestId * @return */ public static boolean unLock(JedisPool jedisPool, String lockKey, String requestId) { validParam(jedisPool, lockKey, requestId, 1); String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Jedis jedis = null; try { jedis = jedisPool.getResource(); Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (RELEASE_SUCCESS.equals(result)) { return true; } } catch (Exception e) { throw e; } finally { if (null != jedis) { jedis.close(); } } return false; } }
首先Redis的 public String set(final String key, final String value, final String nxxx, final String expx,數據庫