我正在使用spring框架StringRedisTemplate来更新多个线程发生的条目。
public void processSubmission(final String key, final Map<String, String> submissionDTO) {
final String hashKey = String.valueOf(Hashing.MURMUR_HASH.hash(key));
this.stringRedisTemplate.expire(key, 60, TimeUnit.MINUTES);
final HashOperations<String, String, String> ops = this.stringRedisTemplate.opsForHash();
Map<String, String> data = findByKey(key);
String json;
if (data != null) {
data.putAll(submissionDTO);
json = convertSubmission(data);
} else {
json = convertSubmission(submissionDTO);
}
ops.put(key, hashKey, json);
}
在这个json条目中,如下所示,
key (assignmentId) -> value (submissionId, status)
如代码所示,在更新缓存条目之前,我获取当前条目并添加新条目并将它们全部放入。但由于此操作可以在多个线程中执行,因此可能存在竞争条件导致数据丢失的情况。我可以同步上面的方法,但是它将成为RxJava实现的并行处理能力的瓶颈,其中processSubmission方法是通过RxJava在两个异步线程上调用的。
class ProcessSubmission{
@Override
public Observable<Boolean> processSubmissionSet1(List<Submission> submissionList, HttpHeaders requestHeaders) {
return Observable.create(observer -> {
for (final Submission submission : submissionList) {
//Cache entry insert method invoke via this call
final Boolean status = processSubmissionExecutor.processSubmission(submission, requestHeaders);
observer.onNext(status);
}
observer.onCompleted();
});
}
@Override
public Observable<Boolean> processSubmissionSet2(List<Submission> submissionList, HttpHeaders requestHeaders) {
return Observable.create(observer -> {
for (final Submission submission : submissionList) {
//Cache entry insert method invoke via this call
final Boolean status = processSubmissionExecutor.processSubmission(submission, requestHeaders);
observer.onNext(status);
}
observer.onCompleted();
});
}
}
以上将从以下服务API调用。
class MyService{
public void handleSubmissions(){
final Observable<Boolean> statusObser1 = processSubmission.processSubmissionSet1(subListDtos.get(0), requestHeaders)
.subscribeOn(Schedulers.newThread());
final Observable<Boolean> statusObser2 = processSubmission.processSubmissionSet2(subListDtos.get(1), requestHeaders)
.subscribeOn(Schedulers.newThread());
statusObser1.subscribe();
statusObser2.subscribe();
}
}
因此,handleSubmissions每个赋值ID调用多个线程。但是每个主线程创建并调用两个响应式java线程并处理与每个赋值关联的提交列表。
什么是最好的方法,我可以防止redis进入竞争条件,同时保持RxJava实现的性能?有没有办法可以更有效地执行此redis操作?
答案 0 :(得分:0)
您似乎只在最后使用ops
变量执行put
操作,并且可以隔离您需要同步的点。
在我所做的简短研究中,我无法找到HashOperations
是否已经是线程安全的。
但是你可以如何孤立你关注的部分的一个例子就是做一些事情:
public void processSubmission(final String key, final Map<String, String> submissionDTO) {
final String hashKey = String.valueOf(Hashing.MURMUR_HASH.hash(key));
this.stringRedisTemplate.expire(key, 60, TimeUnit.MINUTES);
Map<String, String> data = findByKey(key);
String json;
if (data != null) {
data.putAll(submissionDTO);
json = convertSubmission(data);
} else {
json = convertSubmission(submissionDTO);
}
putThreadSafeValue(key, hashKey, json);
}
并且有一个仅为put
操作同步的方法:
private synchronized void putThreadSafeValue(key, hashKey, json) {
final HashOperations<String, String, String> ops = this.stringRedisTemplate.opsForHash();
ops.put(key, hashKey, json);
}
有很多方法可以做到这一点,但看起来您可以将线程争用限制为put
操作。