Java 自定义类似队列的数据结构上的并发帮助

Java 自定义类似队列的数据结构上的并发帮助,java,multithreading,data-structures,concurrency,Java,Multithreading,Data Structures,Concurrency,我正在尝试实现一种以插入性能为中心的、类似队列的数据结构,该结构必须满足以下要求: 必须是线程安全的 必须能够在不同步的情况下添加到队列 必须能够获取队列的“快照”视图 我的问题是以不需要同步插入的方式获取“快照”视图。因为我可以阻止删除,元素只能添加到末尾,所以获取元素应该不是问题。我经常遇到的问题是,LinkedList的迭代器有一个不可压缩的并发修改快速失败烘焙,并且“LinkedList.get(int)”是O(n) 下面是一个简化的例子,说明了我所从事的应该是一项相当简单的任务 pub

我正在尝试实现一种以插入性能为中心的、类似队列的数据结构,该结构必须满足以下要求:

  • 必须是线程安全的
  • 必须能够在不同步的情况下添加到队列
  • 必须能够获取队列的“快照”视图
  • 我的问题是以不需要同步插入的方式获取“快照”视图。因为我可以阻止删除,元素只能添加到末尾,所以获取元素应该不是问题。我经常遇到的问题是,LinkedList的迭代器有一个不可压缩的并发修改快速失败烘焙,并且“LinkedList.get(int)”是O(n)

    下面是一个简化的例子,说明了我所从事的应该是一项相当简单的任务

    public class SnapshotableQueue<T> {
        private final LinkedList<T> queue = new LinkedList<>();
        private final Object removeLock = new Object();
    
        public void add(T element) {
            queue.add(element);
        }
    
        public T remove() {
            synchronized(removeLock) {
                return queue.remove();
            }
        }
    
        public List<T> getSnapshot() {
            synchronized(removeLock) {
                int length = queue.size();
                List<T> snapshot = new ArrayList<>(length);
    
                ???
    
                return snapshot;
            }
        }
    }
    
    “ArrayList.remove(0)”是O(n)

    在Java中有一个,它是并发包的一部分,似乎完全可以执行您想要的操作


    但请注意,每次插入内容时,它都会创建列表的副本,因此它只应在读得比写得多的情况下使用。

    不要重新发明轮子,使用
    ConcurrentLinkedQueue
    而不是
    LinkedList
    然后使用
    迭代器()
    构建本机线程安全的快照

    然后,您的方法
    getSnapshot
    将非常简单

    public List<T> getSnapshot() {
        return new ArrayList<>(queue);
    }
    
    public List getSnapshot(){
    返回新的ArrayList(队列);
    }
    
    NB:您的代码不是线程安全的,您需要一个同步块来执行方法add toothis,这可能是您在解决方案中获得ConcurrentModificationException的原因#2它实际上是线程安全的,因为我只在末尾添加,正在同步删除。不幸的是,LinkedList迭代器有一个“哑”检查来查看是否有任何更改。如果设计人员能够提供一种方法来指定自己的迭代器,这将是一件很好的事情,它可以省去训练轮。我将以写的方式而不是读的方式,所以这对我来说不起作用。无论如何,谢谢。是的,这是正确的CopyOnWriteArrayList只有当你主要阅读而很少写作时才有意思,否则它也是一个性能杀手,我也建议你这样做。基于javadoc中指向michaels用户空间上该文档的链接,它使用了一种具有单独写锁和读锁的算法(X),它应该提供线程安全和高性能的并发读写访问。在扫描“java.util.concurrent”包时,我简要地看了一下这一点,但出于某种原因,我最终忽略了它。仔细看看JavaDocs,一个标杆博客看起来很棒。谢谢你给我指明了正确的方向。@doge这是一个不同的故事,但是如果T不是线程安全的,并且它被多个线程同时读取和修改,那么你将确实面临这个问题。这就是我所说的。若类不是完全线程安全的,那个么它就不是线程安全的。这个问题也必须考虑。共享非线程安全状态可以通过深度复制实现。
    Iterator<T> iterator = queue.iterator();
    for(int i = 0; i < length; i++)
        snapshot.add(iterator.next());
    
    Change queue to ArrayList
    
    public List<T> getSnapshot() {
        return new ArrayList<>(queue);
    }