Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/333.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 单写多读原语映射_Java_C++_Multithreading_C++11 - Fatal编程技术网

Java 单写多读原语映射

Java 单写多读原语映射,java,c++,multithreading,c++11,Java,C++,Multithreading,C++11,我正在尝试用Java编写一个actor实现。我的设计需要一个高性能的map数据结构,用于查找特定参与者计划在哪个线程上。查找是使用int id完成的。所有参与者都有单独的id。我有以下要求: i) 键是基本整数,而不是整数类 ii)值也是原语。值只能包含在数据结构实例化之前已知的几个数字。值只是线程/核心的id,因此它可以是短的。线程数小于机器上的内核数,因此不能达到非常高的数目 iii)地图由单线程写入,但从多线程读取。我希望我的实现是无锁的,没有任何共享(false或其他)。因此,读取不应涉

我正在尝试用Java编写一个actor实现。我的设计需要一个高性能的map数据结构,用于查找特定参与者计划在哪个线程上。查找是使用int id完成的。所有参与者都有单独的id。我有以下要求:

i) 键是基本整数,而不是整数类

ii)值也是原语。值只能包含在数据结构实例化之前已知的几个数字。值只是线程/核心的id,因此它可以是短的。线程数小于机器上的内核数,因此不能达到非常高的数目

iii)地图由单线程写入,但从多线程读取。我希望我的实现是无锁的,没有任何共享(false或其他)。因此,读取不应涉及对非线程本地内存的任何写入

iv)使用map进行查找的多个读卡器线程的读取将大大超过写入(通过单个线程)的数量

v) 所需的主要操作包括:

  • Set(key,value)
    delete(key,value)
    始终从单个writer线程调用。大多数设置的键最终也会被删除,所以在多次删除后性能不会下降。新的键(参与者ID)将使用递增的整数生成,并表示参与者的创建。删除密钥(参与者id)表示该参与者已退出,并且永远不会复活。这也意味着一个键一旦被删除,就再也不会被设置。重要的是,我们不要在映射中积累死空间,因为将发生删除(参与者退出)

  • Get(key)
    从读卡器线程调用

  • vi)操作
    get(key)
    需要
    最终保持一致
    ,但需要注意一些事项。假设writer线程已将对key1->value1更改为key1->value2。如果其中一个读卡器执行get(键1)并仍然接收value1,则这不是问题。最终它应该会变得有价值。如果writer线程删除了对key1->value1,并且读取器线程上的get(key1)仍然返回value1,也可以。实际上,我的意思是Java的
    putOrderedObject/lazySet/getObjectVolatile
    ,或者C++11的
    std::memory\u order\u released/std::memory\u order\u acquire/std::memory\u order\u release
    可以合并。另一方面,如果确实设置了值,
    get(key1)
    不应返回空值(比如-1)。如果
    get(key1)
    返回空值以满足此要求,我可以调用
    getStrict(key1)
    操作

    我不直接使用图书馆的原因有:

    i) Java集合:它们需要包装类,因此无法满足我的目标(i)和(ii)

    ii)Trove、FastUtil等:它们有原始地图,但不提供任何并发访问设施。它们也不会针对稀疏范围内的值进行优化—在我的例子中,核心数是多少

    iii)Java ConcurrentHashMap/ConcurrentSkipListMap:它们需要包装类,并且不针对单个编写器、多个读取器用例进行优化

    我意识到这些要求很多,因此,如果答案解决了其中一些问题,而对其他一些问题仍然模棱两可,那就好了。给我指点设计的源代码或注释会很好。任何关于取舍的解释都是额外的好处,因为我正在努力学习如何捕鱼

    如果我把我的详细要求归结为几个问题,它们可能是:

    i) 如何针对单个编写器/多个读取器用例进行优化

    ii)如何设计
    get(key)
    getStrict(key)
    操作?这是正确的思考方式吗

    iii)如何设计地图以利用递增键和稀疏值范围

    iv)我如何以最佳方式处理频繁删除?任何大小调整/重新灰化都需要对读卡器线程立即可见,而不是最终可见


    此外,欢迎使用C++/C++11代码回答任何问题。通过一些研究,我应该能够将大多数std::atomic操作转换为Java不安全操作。

    错误共享只来自多个编写器,因为您只有一个编写器,所以编写器之间的共享不应该有问题

    i) 如何针对单个编写器/多个读取器用例进行优化

    您不需要为多个读卡器执行任何特殊操作,在这种情况下,每个线程都有一个数据结构的本地副本。单个编写器是最简单(也是最快)的用例

    因此,Trove和ConcurrentMaps都可以很好地实现这一点。顺便说一句,ConcurrentMap还针对多个编写器进行了优化

    ii)如何设计get(key)和getStrict(key)操作?这是正确的思考方式吗

    您描述的是并发集合现在是如何工作的。我不清楚getStrict有什么不同之处

    iii)如何设计地图以利用递增键和稀疏值范围

    如果您有普通的递增键,也许环形缓冲区是更好的选择。如果您有
    稀疏值
    则只需存储该值

    iv)我如何以最佳方式处理频繁删除

    根据您的操作,环形缓冲区对于删除非常有效。要考虑的主要问题是有一个内存/对象循环策略。这将减少重新分配和垃圾收集的成本

    任何大小调整/重新灰化都需要对读卡器线程立即可见,而不是最终可见

    如果值最终可以是c