可直接访问的数据结构Java

可直接访问的数据结构Java,java,data-structures,concurrency,Java,Data Structures,Concurrency,我有以下情况: 一种只能扩展的数据结构(我只能扩展) 在尾部添加内容) 我需要能够跟踪我已经拥有的元素 看到了(我有一个索引,理想情况下我希望能够开始 从该特定元素再次遍历列表) 我希望读取永远不会被阻塞,并且添加 新元素只锁定队列的尾部,而不是 整个队伍 这是一个被多个线程严重修改的结构 这方面最好的数据结构是什么 阵列列表。这将非常理想,能够直接访问使用索引看到的最后一个元素,但它会导致并发修改异常。我可以使其同步,但希望避免锁定(或除最后一个元素之外的任何锁定,因为它是唯一可能存在并发写入

我有以下情况:

  • 一种只能扩展的数据结构(我只能扩展) 在尾部添加内容)
  • 我需要能够跟踪我已经拥有的元素 看到了(我有一个索引,理想情况下我希望能够开始 从该特定元素再次遍历列表)
  • 我希望读取永远不会被阻塞,并且添加 新元素只锁定队列的尾部,而不是 整个队伍
  • 这是一个被多个线程严重修改的结构

    这方面最好的数据结构是什么

    阵列列表。这将非常理想,能够直接访问使用索引看到的最后一个元素,但它会导致并发修改异常。我可以使其同步,但希望避免锁定(或除最后一个元素之外的任何锁定,因为它是唯一可能存在并发写入以添加新元素的元素)

    ConcurrentLinkedQueue。这将解决我的并发问题,但问题是我必须存储迭代的当前位置,而不是整数索引。问题是它返回一个弱一致的迭代器,但不能保证返回自迭代器创建以来添加到列表中的新对象(来源:javadoc)


    以索引为键的ConcurrentHashMap。这样做的好处是,我可以直接访问与正确索引对应的数据,但存在一个问题,即没有一个“getNext”操作符可以让我有效地遍历从索引到索引+1等元素

    Vectors这将解决我在允许某些内容不会引发并发修改异常并允许直接访问方面的大部分问题。但是,如果所有方法都是同步的,那么与ArrayList相比,性能较差。由于我只想扩展结构,而不在中间插入记录,所以我不愿意去考虑这个重的解决方案,在那里读取也遭受性能的冲击(而在给定的情况下,一个元素的索引从来没有真正改变,所以不需要同步非尾部的读取)

    自定义数据结构:保留要存储的对象数组和指向该数组尾部(最后一个元素集)的指针,插入新对象时,锁定尾部和尾部指向的对象。当对象超过其当前大小时,将执行锁定调整大小操作

    最好的策略/其他更有效的实现是什么?

    该结构可以解决您的问题(java.util.concurrent)

    • CopyOnWriteArrayList
      s是线程安全的,因为所有的变异操作都是通过创建列表的副本来实现的

    • 避免了
      ConcurrentModificationException
      的问题,因为数组在迭代时不会更改。所谓的
      快照式迭代器
      在创建迭代器时使用对数组状态的引用

    • 如果读操作比写操作多得多,请使用
      CopyOnWriteArrayList
      ,否则请使用
      Vector

    • Vector
      CopyOnWriteArrayList
      具有较长的写入延迟(由于复制)但没有读取延迟时,会为每个操作引入较小的同步延迟

    • Vector
      在迭代时需要显式同步(因此不能同时执行写入操作),
      CopyOnWriteArrayList
      不需要

    ArrayList。这将非常理想,能够直接访问使用索引看到的最后一个元素,但它会导致并发修改异常。我可以使其同步,但希望避免锁定(或除最后一个元素之外的任何锁定,因为它是唯一可能存在并发写入以添加新元素的元素)

    您可以使用一个临时列表来放置要添加的对象,当读取对象解除阻止时,您可以将tmpList的内容添加到ArrayList中

    如前所述,我认为
    java.util.Vector
    符合您的三点要求

  • 可以使用方法
    add
    扩展向量,该方法在 名单
  • 向量有方法
    get(index)
    来检索特定索引处的具体元素
  • 向量是线程安全的:

  • 这听起来很像您需要一个Distributor,或者简单地说,就是无锁队列。我希望我能在这里添加一个例子,但我昨天才开始研究它。我也可以告诉你它是如何工作的,或者你可以在这里阅读更好的解释:

    一般的想法是,这是完全无锁的,它只使用CAS寄存器(在java AtomicXXX中)。我只是爱上了这个想法


    使用索引作为键的ConcurrentHashMap可以解决您的问题,但您需要做的工作很少

    就像下面的伪代码一样

    Map<Integer , ConfiguredObject > myMap = new ConcurrentHashMap<Integer,ConfiguredObject >();
    
    class ConfiguredObject 
    {
       YourObject Object;// the object which you want to map for map[key];
       ConfiguredObject Next;//the object which you want to map for map[key+1];
       ConfiguredObject Previous;//the object which you want to map for map[key-1];
       YourObject NextObject;
       YourObject PrevObject;
    }
    
    您所需要做的就是定义可配置对象并谨慎地编写相应的构造函数

    希望这对你有帮助

    我将提供,因为:

    1) 这是并发的

    2) 这是一个
    集合

    3) 它也是
    NavigableSet
    ,因此也是
    SortedSet


    这给了你很大的灵活性,其中大部分你可能不需要。但是除了“你不能添加已经存在的项目”(我不知道这是一个问题,还是一个恩惠)之外,它似乎满足了你的所有要求。

    研究这个问题,我找到了与@MissingNumber相同的解决方案

    使用ConcurrentHashMap作为备份数据结构:

    • 非阻塞读取
    • 线程安全附加
    要按索引添加随机访问,请使用AtomicInteger来维护索引并将其作为
    myMap.get(key).Next ;
    myMap.get(key).Previous ;
    
    public class ConcurrentListMap {
    
      private final ConcurrentHashMap<Integer, Object> backingMap;
      private final AtomicInteger index;
    
      public ConcurrentListMap() {
        backingMap = new ConcurrentHashMap();
        index = new AtomicInteger(0);
      }
    
      public int append(final Object value) {
        final int newIndex = index.incrementAndGet();
        backingMap.put(newIndex, value);
        return newIndex;
      }
    
      public Object get(final int entry) {
        return backingMap.get(entry);
      }
    
      public int getTailIndex() {
        return index.get();
      }
    }