Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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
JavaSpring是否会以线程安全的方式在Redis中设置和获取值?_Java_Multithreading_Spring Boot_Redis - Fatal编程技术网

JavaSpring是否会以线程安全的方式在Redis中设置和获取值?

JavaSpring是否会以线程安全的方式在Redis中设置和获取值?,java,multithreading,spring-boot,redis,Java,Multithreading,Spring Boot,Redis,我需要存储经常更改的ArrayList的值,并在应用程序崩溃时保留这些值。我正在开发的应用程序已经使用了Redis数据库,所以它看起来是一个不错的选择 下面,我简要介绍了一个spring引导控制器的示例,它连接到Redis的localhost实例并使用它存储序列化对象。可以从控制器端点或通过每5秒运行一次的计划作业修改该值。如果对localhost:8080/test执行一系列get请求,您将看到计划作业一次从ArrayList中删除一个项目 是否有可能遗漏某个值,或者在这里发生不安全的情况?我

我需要存储经常更改的ArrayList的值,并在应用程序崩溃时保留这些值。我正在开发的应用程序已经使用了Redis数据库,所以它看起来是一个不错的选择

下面,我简要介绍了一个spring引导控制器的示例,它连接到Redis的localhost实例并使用它存储序列化对象。可以从控制器端点或通过每5秒运行一次的计划作业修改该值。如果对
localhost:8080/test
执行一系列get请求,您将看到计划作业一次从ArrayList中删除一个项目

是否有可能遗漏某个值,或者在这里发生不安全的情况?我担心,如果计划作业试图同时修改对象或设置Redis值,那么计划作业可能会与控制器端点所做的更改发生冲突,特别是如果网络速度减慢,但我不确定这是否真的是一个问题。在我的本地主机上运行时,一切似乎都很好,但我仍然持怀疑态度

我读了一篇关于线程安全的文章,但它并没有回答在这种特殊情况下是否需要这些东西。我也知道,但我想,如果命令以错误的顺序发送到Redis怎么办

我在想,如果这个实现有问题,那么Lombok的@Syncronized注释可能对IO的抽象方法有用。我感谢您的投入和花费的时间

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;

@RestController
public class Example {

    RedisClient redisClient = RedisClient.create("redis://localhost:6379/");
    StatefulRedisConnection<String, String> connection = redisClient.connect();
    RedisCommands<String, String> redis = connection.sync();

    Gson gson = new Gson();

    ArrayList<String> someList = new ArrayList<>();


    public Example() {
        if(redis.exists("somekey") == 1){
            Type collectionType = new TypeToken<Collection<VideoDAO>>(){}.getType();
            someList = new ArrayList<>(gson.fromJson(redis.get("somekey"), collectionType));
        }
    }

    @GetMapping("/test")
    public void addToSomeList(){
        someList.add("sample string");
        redis.set("somekey",gson.toJson(someList));
        System.out.println("New item added. " + someList.size() + " items in array");
    }

    @Scheduled(fixedRate = 5000)
    public void popFromSomeList() {
        if (!someList.isEmpty()) {
            someList.remove(0);
            redis.set("somekey", gson.toJson(someList));
            System.out.println("Item removed. " + someList.size() + " items in array");
        }
    }

}
import com.google.gson.gson;
导入com.google.gson.reflect.TypeToken;
导入io.莴苣.core.RedisClient;
导入io.莴苣.core.api.StatefulRedisConnection;
导入io.莴苣.core.api.sync.redis命令;
导入org.springframework.scheduling.annotation.Scheduled;
导入org.springframework.web.bind.annotation.GetMapping;
导入org.springframework.web.bind.annotation.RestController;
导入java.lang.reflect.Type;
导入java.util.ArrayList;
导入java.util.Collection;
@RestController
公开课范例{
RedisClient RedisClient=RedisClient.create(“redis://localhost:6379/");
StatefulRedisConnection=redisClient.connect();
redis=connection.sync();
Gson Gson=新的Gson();
ArrayList someList=新的ArrayList();
公共示例(){
if(redis.exists(“somekey”)==1){
Type collectionType=new-TypeToken(){}.getType();
someList=newArrayList(gson.fromJson(redis.get(“somekey”),collectionType));
}
}
@GetMapping(“/test”)
public void addToSomeList(){
添加(“示例字符串”);
set(“somekey”,gson.toJson(someList));
System.out.println(“添加了新项。”+someList.size()+“数组中的项”);
}
@计划(固定利率=5000)
public void popFromSomeList(){
如果(!someList.isEmpty()){
someList.remove(0);
set(“somekey”,gson.toJson(someList));
System.out.println(“项已删除。”+someList.size()+“数组中的项”);
}
}
}

我使用的是java 1.8。

最明显的是
someList
不是线程安全的,因此即使忽略Redis,代码也会被破坏

假设我们使用
Collections.synchronizedList(newarraylist())使其线程安全。然后,
add
pop
仍然不是原子的,尽管这对功能来说可能不太重要。您可以(例如)以以下执行方式结束

someList.add("sample string");
someList.remove(0);
redis.set("somekey", gson.toJson(someList));
redis.set("somekey", gson.toJson(someList));
消息可能会令人困惑,因为它可能会显示“添加了新项目。数组中有4个项目”、“添加了新项目。数组中有4个项目”、“删除了项目。数组中有4个项目”,因为添加/删除操作发生在打印之前

因此,为了使给定代码(或类似代码)具有适当的功能,您必须同步这些方法或使用显式共享锁。有可能以错误的顺序发送命令,但在给定的示例中(假设列表是线程安全的),不存在真正的危险,因为这只会导致相同数据的重复集