- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要存储经常更改的 ArrayList 的值,并在应用程序崩溃时保留这些值。我正在开发的应用程序已经使用了 Redis 数据库,因此它似乎是一个不错的选择。
下面,我总结了一个 Spring Boot Controller 的最小示例,该 Controller 连接到 Redis 的本地主机实例并使用它来存储序列化对象。可以从 Controller 端点或通过每 5 秒运行一次的计划作业来修改该值。如果您对 localhost:8080/test
执行一系列获取请求,您将看到计划的作业一次从 ArrayList 中删除一个项目。
是否有可能会丢失某个值,或者发生非线程安全的情况?我担心如果 Controller 端点尝试同时修改对象或设置 Redis 值,计划的作业可能会与 Controller 端点所做的更改发生冲突,尤其是在网络速度减慢的情况下,但我不确定这实际上是否会发生一个问题。一切似乎都工作正常,因为它在我的本地主机上运行,但我仍然持怀疑态度。
我读到this文章等内容涉及线程安全,但它没有回答这些事情对于这种特殊情况是否是必要的。我还知道 Redis read and writes are atomic ,但我想,如果命令以错误的顺序发送到 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");
}
}
}
我使用的是java 1.8。
最佳答案
最明显的是someList
不是线程安全的,因此即使您忽略 Redis,代码也会被破坏。
假设我们使用 Collections.synchronizedList(new ArrayList<>());
使其线程安全。然后add
和pop
仍然不是原子的,尽管这对于功能来说可能不太重要。您最终可能会得到(例如)以下类型的执行
someList.add("sample string");
someList.remove(0);
redis.set("somekey", gson.toJson(someList));
redis.set("somekey", gson.toJson(someList));
并且消息可能会令人困惑,因为它可能显示“添加了新项目。数组中的 4 个项目”、“添加了新项目。数组中的 4 个项目”、“删除了项目。数组中的 4 个项目”,由于添加/删除打印之前发生的事情。
因此,为了给定代码(或类似代码)的正确功能,您必须同步方法或使用显式共享锁。有可能以错误的顺序发送命令,但在给定的示例中(假设列表是线程安全的),就不存在真正的危险,因为它只会导致相同数据的重复集。
关于java - Java Spring Boot 会以线程安全的方式在 Redis 中设置和获取值吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60958504/
我是一名优秀的程序员,十分优秀!