Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java compareAndSet在redis中的内部工作原理_Java_Spring_Redis - Fatal编程技术网

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);