java集合的不可修改的包装器是否使它们对线程安全?

时间:2008-09-17 21:49:09

标签: java multithreading collections unmodifiable

我需要使ArrayLists的ArrayList线程安全。我也无法让客户对集合进行更改。不可修改的包装器是否会使线程安全?或者我需要在集合上使用两个包装器吗?

9 个答案:

答案 0 :(得分:10)

这取决于。包装器只会阻止对它包装的集合的更改,而不是对集合中的对象的更改。如果您有ArrayList的ArrayList,则需要单独包装全局List及其每个元素列表,并且您可能还必须对这些列表的内容执行某些操作。最后,您必须确保原始列表对象不会更改,因为包装器仅阻止通过包装器引用而不是原始对象进行更改。

在这种情况下,您不需要同步包装器。

答案 1 :(得分:5)

关于相关主题 - 我看过几个回复建议使用同步收集以实现线程安全。 使用集合的同步版本并不会使其“线程安全” - 尽管每个操作(插入,计数等)在组合两个操作时都受到互斥锁的保护,但不能保证它们会以原子方式执行。 例如,以下代码不是线程安全的(即使使用同步队列):

if(queue.Count > 0)
{
   queue.Add(...);
}

答案 2 :(得分:2)

不可修改的包装器仅阻止更改它适用的列表结构。如果此列表包含其他列表,并且您有线程尝试修改这些嵌套列表,那么您不会受到并发修改风险的保护。

答案 3 :(得分:1)

通过查看收藏源,看起来不可修改使其同步。

static class UnmodifiableSet<E> extends UnmodifiableCollection<E>
                 implements Set<E>, Serializable;

static class UnmodifiableCollection<E> implements Collection<E>, Serializable;

同步类包装器中有一个互斥对象来执行同步部分,所以看起来你需要同时使用它们来获取两者。或者自己滚动!

答案 4 :(得分:1)

我相信因为UnmodifiableList包装器将ArrayList存储到final字段,所以包装器上的任何读取方法都会看到列表构建时的列表,只要在创建包装器后未修改列表,并且只要包装器内的可变ArrayLists未被修改(包装器无法保护)。

答案 5 :(得分:1)

根据定义,不可变对象是线程安全的(假设没有人保留对原始集合的引用),因此同步是必要的。

使用Collections.unmodifiableList()包装外部ArrayList 防止客户端更改其内容(从而使其成为线程 安全),但内部ArrayLists仍然是可变的。

使用Collections.unmodifiableList()包装内部ArrayLists 防止客户改变他们的内容(从而使他们 线程安全),这是你需要的。

如果此解决方案导致问题(开销,内存使用等),请告诉我们; 其他解决方案可能适用于您的问题。 :)

编辑:当然,如果列表被修改,它们不是线程安全的。我假设没有进行进一步的编辑。

答案 6 :(得分:1)

如果安全地发布了不可修改的视图,它将是线程安全的,并且在发布不可修改的视图之后永远不会修改可修改的原始文件(包括集合中递归包含的所有对象!)。

如果您想继续修改原始文件,那么您可以创建集合的对象图的防御副本并返回其不可修改的视图,或者使用固有的线程安全列表开始,并返回不可修改的观点。

如果你打算之后仍打算访问未同步的列表,那么你不能返回一个unmodifiableList(synchonizedList(theList));如果多个线程之间共享可变状态,则所有线程在访问该状态时必须在相同的锁上同步。

答案 7 :(得分:0)

如果符合以下条件,这是必要的:

  1. 仍有对原始可修改列表的引用。
  2. 可以通过迭代器访问该列表。
  3. 如果您打算仅通过索引从ArrayList读取,则可以认为这是线程安全的。

    如有疑问,请选择同步包装。

答案 8 :(得分:0)

不确定我是否明白你要做什么,但我会说大多数情况下的答案都是“不”。

如果你设置了ArrayList的ArrayList和两者,外部和内部列表在创建后永远不会被更改(并且在创建期间只有一个线程可以访问内部和外部列表),它们可能是包装器的线程安全(如果两个,外部和内部列表都以这样的方式包装,即无法修改它们)。 ArrayLists上的所有只读操作很可能是线程安全的。但是,Sun并不保证它们是线程安全的(也不是用于只读操作),因此即使它现在可能正常工作,它也可能在未来中断(如果Sun创建一些内部的话)例如,缓存数据以便更快地访问。