redis是做为缓存的主流选择,这里主要拿它和memcached比较一下:
redis是单线程模型,没有锁的概念,不存在资源竞争,对于同一key是原子操作;memcached是多线程模型。利用自身的cas操作实现锁的操作(等同与乐观所,每一个key对应会产生一个64bit的标记,当某个线程更新key的值是会比较这个标记有没有变化,有变化则放弃更新);
redis中有一个setnx函数(set if not exist,当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0),可以利用它来实现一个简单的分布式锁;核心代码如下:
可以利用以上对象对共享资源进行锁定,功能类似于java内置锁ReentrantLock
其他常见用法:
以上利用setnx的特性实现表单重复提交的问题。避免请求密集造成数据重复
redis是单线程模型,没有锁的概念,不存在资源竞争,对于同一key是原子操作;memcached是多线程模型。利用自身的cas操作实现锁的操作(等同与乐观所,每一个key对应会产生一个64bit的标记,当某个线程更新key的值是会比较这个标记有没有变化,有变化则放弃更新);
redis中有一个setnx函数(set if not exist,当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 已经存在,则 SETNX 不做任何动作,并返回0),可以利用它来实现一个简单的分布式锁;核心代码如下:
public class RedisLock implements Lock {
@Autowired
protected StringRedisTemplate redisTemplate;
private static final Logger logger = Logger.getLogger(RedisLock.class);
// lock flag stored in redis
private static final String LOCKED = "TRUE";
// timeout(ms)
private static final long TIME_OUT = 30000;
// lock expire time(s)
public static final int EXPIRE = 60;
// private Jedis jedis;
private String key;
// state flag
private volatile boolean locked = false;
private static ConcurrentMap<String, RedisLock> map = Maps.newConcurrentMap();
public RedisLock(String key) {
this.key = "_LOCK_" + key;
redisTemplate = (StringRedisTemplate) ApplicationContextHolder.getBean("redisTemplate");
}
public static RedisLock getInstance(String key) {
return map.getOrDefault(key, new RedisLock(key));
}
public void lock(long timeout) {
long nano = System.nanoTime();
timeout *= 1000000;
final Random r = new Random();
try {
while ((System.nanoTime() - nano) < timeout) {
if (redisTemplate.getConnectionFactory().getConnection().setNX(key.getBytes(), LOCKED.getBytes())) {
redisTemplate.expire(key, EXPIRE, TimeUnit.SECONDS);
locked = true;
logger.debug("add RedisLock[" + key + "].");
break;
}
Thread.sleep(3, r.nextInt(500));
}
} catch (Exception e) {
}
}
@Override
public void unlock() {
if (locked) {
logger.debug("release RedisLock[" + key + "].");
redisTemplate.delete(key);
}
}
@Override
public void lock() {
lock(TIME_OUT);
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public Condition newCondition() {
return null;
}
@Override
public boolean tryLock() {
return false;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
}
可以利用以上对象对共享资源进行锁定,功能类似于java内置锁ReentrantLock
其他常见用法:
if(getRedisClient().setnx("需要锁定的key", value)>0){
return "重复调用";
}
以上利用setnx的特性实现表单重复提交的问题。避免请求密集造成数据重复