Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用于有序数据访问的Java HashMap_Java_Multithreading - Fatal编程技术网

用于有序数据访问的Java HashMap

用于有序数据访问的Java HashMap,java,multithreading,Java,Multithreading,我正在编写一个Java应用程序,面临生产者-消费者问题,并使用HashMap确保消费者以正确的顺序读取数据。但是,我不确定这是否是一种有效的方法: 程序A和程序B是不同的进程,使用套接字连接进行通信。程序B生成线程T。程序A通过套接字连接不断向程序B发送二进制数据。程序A接收二进制数据并放入列表中。同时,线程(T)将从列表中逐个读取数据 每个数据都与一个顺序id(1,2,3,4,5)相关联,线程T应该以相同的顺序读取数据。例如,它无法读取订单id为3且在2之前的数据。问题是程序A可能无法以正确的

我正在编写一个Java应用程序,面临生产者-消费者问题,并使用HashMap确保消费者以正确的顺序读取数据。但是,我不确定这是否是一种有效的方法:

程序A和程序B是不同的进程,使用套接字连接进行通信。程序B生成线程T。程序A通过套接字连接不断向程序B发送二进制数据。程序A接收二进制数据并放入列表中。同时,线程(T)将从列表中逐个读取数据

每个数据都与一个顺序id(1,2,3,4,5)相关联,线程T应该以相同的顺序读取数据。例如,它无法读取订单id为3且在2之前的数据。问题是程序A可能无法以正确的顺序发送数据

我选择hashmap来存储数据,key是order id,value是二进制数据。线程T有一个专用计数器,并保持如下读取数据:

counter=1
while(stop)
  synchronize(mutexobj){
      if(!hashmap.containsKey(counter))
           wait();
      hashmap.get(counter++)
  }
通过这种方式,线程T将阻塞,直到hashmap中有数据可用,且之前的顺序id为+1

然而,我的问题是,HashMap是解决这个问题的最佳数据结构吗?我不能使用普通数组,因为我不知道程序A将发送多少数据


提前谢谢

解决这个问题有很多不同的方法,你的方法肯定会奏效。不过,您有一个主要问题:需要循环if语句

如果您由于某种原因过早地从
wait()
中醒来,即使映射尚未包含您正在等待的值,您也将继续

while(stop) {
  synchronized(mutexobj) {
    while(!hashmap.containsKey(counter)) {
      wait();
    }
    hashmap.get(counter++);
  }
}
不过,我可能会做一些完全不同的事情,因为我不喜欢直接处理wait/notify

我的解决方案可能是在接收方中保留所有传入消息的有序缓存,而这些消息不是下一个顺序,然后将顺序中的所有消息推送到LinkedBlockingDeque,让您的消费者在队列中等待

// Receiver
TreeSet<Message> cache = new TreeSet<>(new OrderMessagesByIndexComparator());
Message message;
while(run) {
  message = receive();
  cache.add(message);
  Iterator<Message> it = cache.iterator();
  while(it.hasNext()) {
    Message m = it.next();
    if(m.index == next) {
      next++;
      it.remove();
      queue.add(m);
    } else {
      break;
    }
  }
}

// Message consumer
while(run) {
  message = queue.take();
}
//接收机
TreeSet cache=newtreeset(newordermessagesbyindexcomparator());
信息;
while(运行){
消息=接收();
cache.add(消息);
Iterator it=cache.Iterator();
while(it.hasNext()){
消息m=it.next();
如果(m.index==下一个){
next++;
it.remove();
添加(m);
}否则{
打破
}
}
}
//消息消费者
while(运行){
message=queue.take();
}

您是否考虑过使用队列数据结构?可以从一端插入,也可以从另一端删除。阻塞队列可能更适合您的情况。

与您想要的类似,只是它是面向时间的。按序列id排序的自定义阻塞队列将遵循类似的实现模式。如果优化,O(lgn)优先级队列可以替换为O(1)环形缓冲区,因为序列是确定的。这将提供一个可重用的抽象,可能被命名为
SequencedBlockingQueue

我将调整参与者模型来解决这个问题,而不是担心同步和阻塞。当参与者收到消息时,他们可以抓住一条线索,检查消息是否有序。如果没有,则将其存储在某个地方供以后使用。

我无法使用队列,因为进程A可能没有按顺序发送数据,因此线程T可以按顺序从队列中读取数据。非常感谢!另一个问题是,每当我想要快速查找时,使用哈希表好吗?实际上,在我的程序中,键不仅是order id,而且是一个warpper对象,它包含order id以及其他三个字符串,它们一起就像数据库中的复合键。哈希表对那个senario有好处吗?假设我有一个完美的哈希代码函数,我还需要注意hashmap吗?+1用于使用缓冲区,但为什么要将缓冲区保留为映射?树集将使您的性能从常量降低到日志。@SophiaWeng:您通常不需要担心哈希表/映射的性能。散列冲突会发生,只要不太干扰映射的增长参数,您就不会注意到查找是否立即返回或必须在具有相同(截断)散列的2-3个对象之间进行选择@MateuszDymczyk:我认为循环变得更容易遵循。我想如果您真的想要插入的O(1)性能,您可以使用类似
while(cache.containsKey(next)){…}
的方法来实现它。