在Java上的Redis哈希中的列表

问题描述 投票:2回答:2

我正在将Spring与Redis一起使用,并且正在使用哈希中的列表。一切都在一个线程上运行良好,当我不得不用多个实例更新列表值时,问题就来了。

这是我的代码,可从哈希中获取价值:

public void put(String hashName, int key , List<myObj> myList) {
        redis.opsForHash().put(hashName, String.valueOf(key), myList);
        }

public List<myObj> get(String hashName, string key) {
    Object map = redis.opsForHash().get(hashName,key);
    if (map==null) {
        log.info("no keys found");
        return new ArrayList<myObj>();
    }
    List<myObj> myList= mapper.convertValue(map, new TypeReference<List<myObj>(){});
    return myList;
}

我要执行的更新是:

List<myObj> myList= hash.get(hashName,key);
myList.add(obj);
hash.put(hashName, key, myList);

[当有多个实例时,我会出现种族状况。有没有办法以原子方式更新列表值?

java spring hash concurrency redis
2个回答
0
投票

您当前的实现不好,因为您在put()中更新了整个列表。如果许多线程想要将单个元素添加到列表中,则它们首先获取当前列表,然后添加一个元素,然后放置新列表。每个线程将覆盖前一个的结果,最后一个取胜。 synchronized的使用在这里无关紧要。

解决方案>>

不要替换整个列表。而是将一个元素添加到列表中。删除方法put()并添加一个新的方法,如下所示:

public synchronized void add(String hashName, int key, myObj element) {
    List<myObj> myList;
    Object map = redis.opsForHash().get(hashName,key);
    if (map != null) {
        myList= mapper.convertValue(map, new TypeReference<List<myObj>(){});
    } else {
        myList = new ArrayList<myObj>();
    }
    myList.add(element);
    redis.opsForHash().put(hashName, String.valueOf(key), myList);
}

此外,请确保没有尝试直接修改列表的步骤,并且添加元素的唯一方法是使用方法add()。使用Collections.unmodifiableList()

public List<myObj> get(String hashName, string key) {
    Object map = redis.opsForHash().get(hashName,key);
    if (map==null) {
        log.info("no keys found");
        return new ArrayList<myObj>();
    }
    List<myObj> myList= mapper.convertValue(map, new TypeReference<List<myObj>(){});
    return Collections.unmodifiableList(myList);
}

-1
投票

您可以修改put()方法以使其同步。这样,所有调用put()的线程都将首先需要获得单个共享锁(在下面的示例中,它将在this上)。如果两个线程尝试更新Redis中的相同密钥,那么一个线程将不得不等待另一个线程完成。

© www.soinside.com 2019 - 2024. All rights reserved.