使用RxJava异步线程实现防止竞争条件

使用RxJava异步线程实现防止竞争条件,java,spring,multithreading,redis,rx-java,Java,Spring,Multithreading,Redis,Rx Java,我使用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.

我使用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);
}
如代码中所示,在更新缓存项之前,我获取当前项并添加新项,然后将它们全部放入。但由于此操作可以在多个线程中执行,所以可能会出现争用条件导致数据丢失的情况。我可以同步上述方法,但这将成为RxJava实现的并行处理能力的瓶颈,在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();
        });
    }

} 
类进程提交{
@凌驾
公共可观察的processSubmissionSet1(列表submissionList、HttpHeaders和requestHeaders){
返回可观察的。创建(观察者->{
(最后提交:提交名单){
//通过此调用调用缓存项插入方法调用
最终布尔状态=processSubmissionExecutor.processSubmission(提交,RequestHeader);
onNext观察员(地位);
}
observer.onCompleted();
});
}
@凌驾
公共可观察的processSubmissionSet2(列表submissionList、HttpHeaders和requestHeaders){
返回可观察的。创建(观察者->{
用于(最终提交:提交清单){
//通过此调用调用缓存项插入方法调用
最终布尔状态=processSubmissionExecutor.processSubmission(提交,RequestHeader);
onNext观察员(地位);
}
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();
    }       
}
classmyservice{
公共无效可处理的提交(){
最终可观察状态obser1=processSubmission.processSubmissionSet1(SubListTos.get(0),requestHeaders)
.subscribeOn(Schedulers.newThread());
最终可观察状态obser2=processSubmission.processSubmissionSet2(SubListTos.get(1),RequestHeader)
.subscribeOn(Schedulers.newThread());
statusObser1.subscribe();
statusObser2.subscribe();
}       
}
所以handleSubmissions是用每个分配id的多个线程调用的。但是每个主线程是创建并调用两个反应性java线程,并处理与每个分配关联的提交列表


在保持RxJava实现性能的同时,我能防止redis进入竞争状态的最佳方法是什么?有什么方法可以更有效地执行此redis操作吗?

看起来您只是在最后使用
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
操作上。

看起来您只是在最后使用
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);
}