Java compareAndSet在redis中的内部工作原理
Java compareAndSet在redis中的内部工作原理,java,spring,redis,Java,Spring,Redis,spring数据redis模块包含RedisAtomicLong类 在这节课上你可以看到 public boolean compareAndSet(long expect, long update) { return generalOps.execute(new SessionCallback<Boolean>() { @Override @SuppressWarnings("unchecked") public Boole
spring数据redis
模块包含RedisAtomicLong
类
在这节课上你可以看到
public boolean compareAndSet(long expect, long update) {
return generalOps.execute(new SessionCallback<Boolean>() {
@Override
@SuppressWarnings("unchecked")
public Boolean execute(RedisOperations operations) {
for (;;) {
operations.watch(Collections.singleton(key));
if (expect == get()) {
generalOps.multi();
set(update);
if (operations.exec() != null) {
return true;
}
}
{
return false;
}
}
}
});
}
public boolean compareAndSet(长时间期望,长时间更新){
返回generalOps.execute(newsessioncallback(){
@凌驾
@抑制警告(“未选中”)
公共布尔执行(RedisOperations){
对于(;;){
操作.监视(集合.单例(键));
if(expect==get()){
generalOps.multi();
设置(更新);
if(operations.exec()!=null){
返回true;
}
}
{
返回false;
}
}
}
});
}
我的问题是它为什么有效
generalOps.multi()
在调用get()
后启动事务。这意味着两个不同的线程(甚至客户端)有可能改变值,并且它们都会成功
是操作。监视以某种方式阻止它?JavaDoc并没有解释这个方法的用途
附言:小问题:为什么(;;)
?总有一次迭代
是不是有什么办法阻止了它
对。查看密钥后,如果在事务完成之前修改了密钥,EXEC
将失败。因此,如果EXEC
成功,其他人将保证该值不变
为什么是(;)?总有一次迭代
在您的例子中,无限循环似乎是多余的
但是,如果要实现检查和设置操作以使用旧值修改值,则需要无限循环。请从以下位置检查此示例:
由于执行可能失败,您需要在一个循环中重试整个过程,直到成功。问:操作是否正常。观察是否以某种方式阻止它?
是。
引述自:
WATCH用于为Redis事务提供检查和设置(CAS)行为
监视监视的键,以便检测针对它们的更改。如果在EXEC命令之前修改了至少一个关注的密钥,则整个事务将中止,EXEC将返回一个Null回复,通知事务失败
您可以从该文档中了解有关Redis事务的更多信息
问:为什么是(;)?总有一次迭代。
你发布的代码似乎很旧。从Google的缓存中,我看到了您提供的代码,它可以追溯到2012年10月15日
最新的代码看起来大不相同:
RedisAtomicLong。compareAndSet
实现不是最佳的,因为它需要5个Redis请求
-Redis Java client提供了更高效的实现
org.redisson.RedissonAtomicLong#compareAndSetAsync
使用原子求值脚本实现的方法:
"local currValue = redis.call('get', KEYS[1]); "
+ "if currValue == ARGV[1] "
+ "or (tonumber(ARGV[1]) == 0 and currValue == false) then "
+ "redis.call('set', KEYS[1], ARGV[2]); "
+ "return 1 "
+ "else "
+ "return 0 "
+ "end",
此脚本只需要对Redis发出一次请求
用法示例:
RAtomicLong atomicLong = redisson.getAtomicLong("myAtomicLong");
atomicLong.compareAndSet(1L, 2L);
RAtomicLong atomicLong = redisson.getAtomicLong("myAtomicLong");
atomicLong.compareAndSet(1L, 2L);