【问题标题】:What is a thread-safe List implementation that allows Collections.sort什么是允许 Collections.sort 的线程安全 List 实现
【发布时间】:2016-08-22 07:00:01
【问题描述】:

我必须编写一个需要列表的程序。此列表在其实现中需要是线程安全的(主要是为了避免 ConcurrentModificationException),但还需要允许 Collections.sort() 要应用的方法,出于 API 原因。

CopyOnWriteArrayList 满足前者,但不满足后者,我能找到的其他实现允许后者但不允许前者。

Java 有适合我的列表实现吗?

编辑:需要注意的重要一点是,不幸的是,我的代码需要与 Java 6 兼容。

【问题讨论】:

  • 是否可以选择使用 3rd 方库?
  • @Fildor 如果它们是轻量级的,它可能是。
  • ConcurrentSkipListSet 会成为候选人吗?没关系 - 只需阅读您关于明确调用 API 的评论 Collections.sort() :(
  • 不幸的是,从层次上讲,这似乎是 Set 的实现,而不是 List 的实现。
  • 使用暴露add()/delete()/sort()/getList()/clearList() 方法的单例。其中一些方法应该是同步的,而其他方法应该有标志来允许或不允许操作(如排序)不能工作,除非没有调用 add/del。你可以使用一些布尔标志来处理这个

标签: java sorting collections concurrency


【解决方案1】:

我想知道这在概念层面上是否真的可行:为了使 sort 操作保持一致,我希望 整个 列表对于任何添加/都被阻止在排序进行时删除。

但 Collections.sort() 不知道它在工作时需要锁定整个列表。你给它一个列表,如果另一个线程同时试图修改列表......祝你好运。

或者换个角度来看:一个“线程安全”的列表应该如何理解它现在正处于被排序的过程中;所以 - 一些访问(如交换元素)很好;但其他(如添加/删除)元素不是?!

换句话说:我认为你只能这样做:选择任何“线程安全”列表实现;然后你必须把你自己的包装器放在那个地方

  1. “锁定”列表以进行更改
  2. 分拣是否有效
  3. “解锁”列表

当然,对于“2”;您可以随意使用 Collections.sort()。

或者,如果您使用的是 Java8 - 您使用 CopyOnWriteArrayList 及其已经实现的 sort() 方法(这证明了我的观点:只有在 在运行排序操作时拥有列表!)。

给出您的最新评论:当然,您可以手动将 Java8 版本的 CopyOnWriteArrayList“反向移植”到您的环境中并使用它;但当然,这无济于事;据我了解,Java6-Collections.sort() 将不会从该类调用新的 sort() 方法。

所以,您的需求总和似乎无法解决;您将不得不硬着头皮在自己的代码中完成大部分工作。

【讨论】:

  • 不幸的是,API 实现将专门尝试对其调用 Collections.sort()。我无法改变这一点。我还不得不维护与 Java 6 兼容的代码库。
【解决方案2】:

好吧,CopyOnWriteArrayList 在排序时会锁定整个集合(用于插入)。没有?

看起来你很擅长 CopyOnWriteArrayList。下面是这个类的sn-p -

public void sort(Comparator<? super E> c) {
    final ReentrantLock lock = this.lock;
    lock.lock();**
    try {
        Object[] elements = getArray();
        Object[] newElements = Arrays.copyOf(elements, elements.length);
        @SuppressWarnings("unchecked") E[] es = (E[])newElements;
        Arrays.sort(es, c);
        setArray(newElements);
    } finally {
        lock.unlock();
    }
}

嗯....既然您已经更新了代码需要与 Java6 兼容的问题,我想说您应该扩展普通列表并使用https://docs.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReadWriteLock.html。在这种类型的锁中,即使其他线程已经获得了 writeLock,也不会阻止读取器读取,并且两个线程可以同时获得“读”锁。

顺便说一句,这种技术需要你的调用者知道 Collection.sort(...) 不应该被调用,因为你必须在你的列表中公开明确的 sort() 方法。嗯....不确定这是否有帮助。

【讨论】:

  • 可以加个链接到这个sn-p的源码吗?
  • 太酷了——这个方法实际上是在 Java8 中添加的;我还不知道。很好的意见!
  • 还要注意,在 Java8 中,Collections.sort(foo) 代表List.sort(...),所以你也应该很好地调用该方法。
  • OP刚刚添加,代码需要Java 6兼容:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-07
  • 1970-01-01
  • 1970-01-01
  • 2010-12-10
相关资源
最近更新 更多