Java 奇怪的榛猫IMap#put()行为

Java 奇怪的榛猫IMap#put()行为,java,multithreading,hazelcast,hazelcast-imap,Java,Multithreading,Hazelcast,Hazelcast Imap,我的基于Hazelcast的程序可以在两种模式下工作:提交者和工作者 提交者通过一些键将一些POJO放入分布式映射,例如:hazelcastInstance.getMap(映射名称).put(键,值) Worker有一个无限循环(带有Thread.sleep(1000L);内部超时),它必须处理映射中的实体。现在我只是在这个循环中打印地图大小 现在问题来了。我启动worker应用程序。然后我同时启动四个提交者(每个提交者向映射添加一个条目并终止其工作)。但在所有提交者应用程序完成后,worker

我的基于Hazelcast的程序可以在两种模式下工作:提交者和工作者

提交者通过一些键将一些POJO放入分布式映射,例如:
hazelcastInstance.getMap(映射名称).put(键,值)

Worker有一个无限循环(带有
Thread.sleep(1000L);
内部超时),它必须处理映射中的实体。现在我只是在这个循环中打印地图大小

现在问题来了。我启动worker应用程序。然后我同时启动四个提交者(每个提交者向映射添加一个条目并终止其工作)。但在所有提交者应用程序完成后,worker应用程序打印任意大小:有时它检测到只添加了一个条目,有时两个,有时三个(实际上它从未看到所有四个条目)

这个简单的流程有什么问题?我在Hazelcast文档中读到,
put()
方法是同步的,因此它保证在返回后,条目被放置到分布式映射,并且被复制。但在我的实验中似乎不是这样

UPD(代码)

提交人:

public void submit(String key) {
    Object mySerializableObject = ...
    IMap<String, Object> map = hazelcastInstance.getMap(MAP_NAME);
    map.putIfAbsent(key, mySerializableObject, TASK_TTL_IN_HOURS, TimeUnit.HOURS);
}
提交人1:

Before: tasksMap.size() = 0
After: tasksMap.size() = 1
提交人2:

Before: tasksMap.size() = 1
After: tasksMap.size() = 4
提交人3:

Before: tasksMap.size() = 1
After: tasksMap.size() = 2
提交人4:

Before: tasksMap.size() = 3
After: tasksMap.size() = 4

嗯,我想,我已经解决了问题。据我所知,
hazelcastInstance.getMap
返回的分布式
IMap
不保证在集群中的所有现有节点上复制数据:数据的某些部分可能会复制到某些节点,另一部分-复制到另一个节点。这就是为什么在我的示例中,一些提交的任务并没有复制到worker节点(永久工作),而是复制到一些其他提交者,这些提交者在提交后终止其执行。因此,这些条目在提交者退出时丢失


我通过将
hazelcastInstance.getMap
替换为
hazelcastInstance.getReplicatedMap
解决了这个问题。此方法返回
ReplicatedMap
,AFAIK保证将放置在其中的条目复制到群集的all节点。因此,现在我的系统中一切正常。

IMap::size方法是一种估计,无论如何,它最终应该会稳定下来。你能分享更多的代码吗?@noctarius,我已经更新了这个问题。你的代码是否使用嵌入成员,他们在提交值后是否真的停止了?我可以想象成员在离开时迅速离开集群以满足备份要求。@DmytroTitov是您的提交者和工作进程,使用Hazelcast客户端api连接到集群,还是在集群节点上运行?如果在提交程序进程中在
map.putIfAbsent
之前和之后打印,报告的大小是多少?@Siddharth它们在同一集群上运行。我在工人和四个提交者身上记录了地图大小(参见问题的更新)。
Before: tasksMap.size() = 1
After: tasksMap.size() = 2
Before: tasksMap.size() = 3
After: tasksMap.size() = 4