put/get-in集合中的Java并发性

put/get-in集合中的Java并发性,java,collections,concurrency,Java,Collections,Concurrency,我通过一个交互式会话+一个在不同线程上运行的私有提要(InputStream)连接到一个外部服务。在交互式会话中,我发送传出消息并接收同步响应,其中一个对象包含不同的字段,其中一个字段是ID和“状态”,用于确认成功或失败。同时,我在私人订阅源上接收到此ID的消息,并进一步更新“状态”。我目前将每个ID的状态信息存储在ConcurrentHashMap中。我必须在这些对象上保持一个正确的事件序列,但我目前正在获得竞争条件,在我接收和处理交互会话上的同步响应之前,我有时会处理和更新私有提要上的对象,

我通过一个交互式会话+一个在不同线程上运行的私有提要(InputStream)连接到一个外部服务。在交互式会话中,我发送传出消息并接收同步响应,其中一个对象包含不同的字段,其中一个字段是ID和“状态”,用于确认成功或失败。同时,我在私人订阅源上接收到此ID的消息,并进一步更新“状态”。我目前将每个ID的状态信息存储在ConcurrentHashMap中。我必须在这些对象上保持一个正确的事件序列,但我目前正在获得竞争条件,在我接收和处理交互会话上的同步响应之前,我有时会处理和更新私有提要上的对象,因此给我留下一个过时和不正确的ID状态

理想情况下,我希望使用PutIfKeyExistOrWait(w timeout)方法创建某种类型的集合,该方法仅在密钥存在或等待时更新值,我可以在处理私有提要上的对象时使用该值


是否有人知道是否有合适的收藏,或者可以为我的问题提出替代方案?谢谢。

我建议您查看收藏。getSynchronized收藏:http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#synchronizedList%28java.util.List%29

这可能会解决您的问题,另一个选项取决于调用的方式,该方法是允许线程安全执行的同步方法,并将确保事务的原子性。看

第三种选择是根据您试图实现的目标,采用乐观或悲观的方法在应用程序中实施并发管理控制。这是3个选项中最复杂的一个,但如果与前面的选项结合使用,将为您提供更大的控制


这实际上取决于您的具体实现。

您可以尝试将处理这种情况的逻辑封装到映射的值中,如下所示:

  • 如果提要线程是第一个为特定id添加值的线程,则该值被认为是不完整的,线程将等待它完成
  • 如果交互式会话线程不是第一个添加值的线程,它会将该未完成的值标记为已完成
  • 从映射中获取不完整的值时,会将其视为不存在
此解决方案基于
putIfAbsent()
的原子性

公共类状态映射{
私有映射映射=新的ConcurrentHashMap();
公共状态getStatus(长id){
StatusHolder=map.get(id);
if(holder==null | | holder.isIncomplete()){
返回null;
}否则{
返回holder.getStatus();
}
}
public void newStatusFromInteractiveSession(长id,状态){
StatusHolder=StatusHolder.newComplete(状态);
if((holder=map.putIfAbsent(id,holder))!=null){
holder.makeComplete(状态);//holder已经存在,请完成它
} 
}
public void newStatusFromFeed(长id,状态){
StatusHolder complete=StatusHolder.newcomplete();
StatusHolder=null;
if((holder=map.putIfAbsent(id,不完整))==null){
holder=未完成;//已添加新的holder,请等待其完成
holder.waitForCompletion();
}
持有人。更新状态(状态);
}
}
公共类身份持有者{
私人身份不稳定;
私有布尔不完全;
私有对象锁=新对象();
私有状态持有者(状态状态,布尔不完整){…}
公共静态状态保持器newComplete(状态状态){
返回新的StatusHolder(状态,false);
}
公共静态状态持有者newcomplete(){
返回新的StatusHolder(null,true);
}
公共布尔值isIncomplete(){return complete;}
public void makeComplete(状态){
已同步(锁定){
这个状态=状态;
不完整=错误;
lock.notifyAll();
}
}
公共作废等待完成(){
已同步(锁定){
while(未完成)lock.wait();
}
}
...
}

您已经有了一些存储ID和最新状态的
ConcurrentHashMap iDAndStatus
。但是,我只允许处理服务的线程在该映射中创建一个新条目

当来自提要的消息到达时,如果ID已经存在于
iDAndStatus
中,它只会修改状态。如果密钥不存在,只需将ID/状态更新临时存储在其他数据结构中,
pendingFeedUpdates

每次在
iDAndStatus
中创建新条目时,请检查
pendingFeedUpdates
以查看是否存在新ID的某些更新


我不确定用于
pendingFeedUpdates
的同步数据结构是什么:您需要按ID检索,但每个ID可能有许多消息,并且希望保持消息的顺序。可能是一个将每个ID与某种类型的同步有序队列相关联的同步哈希映射?

PutIfKeyExistOrWait在以后(当ID已经存在时)收到2个异步通知,但由于竞争条件的原因,以错误的顺序处理它们时不会有帮助。听起来唯一的防弹方法是如果传入的消息有序列号。如果他们没有,我想下一个最好的办法是在收到每封邮件时附上时间戳,然后根据时间戳对状态进行排序。@EliAcherkan谢谢。私有提要上的异步消息在单个线程中接收,因此我可以“保证”这些消息的正确顺序。引起问题的只是同步响应与异步消息。
public class StatusMap {
    private Map<Long, StatusHolder> map = new ConcurrentHashMap<Long, StatusHolder>();

    public Status getStatus(long id) {
        StatusHolder holder = map.get(id);
        if (holder == null || holder.isIncomplete()) {
            return null;
        } else {
            return holder.getStatus();
        }
    }

    public void newStatusFromInteractiveSession(long id, Status status) {
        StatusHolder holder = StatusHolder.newComplete(status);
        if ((holder = map.putIfAbsent(id, holder)) != null) {
            holder.makeComplete(status); // Holder already exists, complete it
        } 
    }

    public void newStatusFromFeed(long id, Status status) {
        StatusHolder incomplete = StatusHolder.newIncomplete();
        StatusHolder holder = null;
        if ((holder = map.putIfAbsent(id, incomplete)) == null) {
            holder = incomplete; // New holder added, wait for its completion
            holder.waitForCompletion();
        }
        holder.updateStatus(status);
    }
}

public class StatusHolder {
    private volatile Status status;
    private volatile boolean incomplete;
    private Object lock = new Object();

    private StatusHolder(Status status, boolean incomplete) { ... }

    public static StatusHolder newComplete(Status status) {
        return new StatusHolder(status, false);
    }

    public static StatusHolder newIncomplete() {
        return new StatusHolder(null, true);
    }

    public boolean isIncomplete() { return incomplete; }

    public void makeComplete(Status status) {
        synchronized (lock) {
            this.status = status;
            incomplete = false;
            lock.notifyAll();
        }
    }

    public void waitForCompletion() {
        synchronized (lock) {
            while (incomplete) lock.wait();
        }
    }
    ...
}