简体   繁体   English

Collections.unmodifiableList上的同步

[英]Synchronization on Collections.unmodifiableList

I have a question. 我有个问题。 I think i know the answer but for some reason i prefer to ask for it here. 我想我知道答案了,但是由于某种原因,我更愿意在这里询问。

So here is the scenario: 所以这是场景:

I have an Object which has a list as a field. 我有一个具有列表作为字段的对象。 Then i have a method that returns the list as an unmodifiableList. 然后,我有一种方法将列表作为unmodifiableList返回。

The Oject class has other methods that add elements to the list. Oject类还有其他将元素添加到列表的方法。

So lets imagine a case where one thread is iterating throught the unmodifiable list and another thread that is adding elements to the list using the Object class method. 因此,让我们想象一种情况,其中一个线程在不可修改的列表中迭代,而另一个线程使用Object类方法在列表中添加元素。

How do i make this thread safe? 如何使该线程安全? If i synchronize the unmodifiableList and the list itselft will it make it thread safe? 如果我同步unmodifiableList和列表本身,它将使其线程安全吗? After all they are two different object where the unmodifiableList has a field which is the naked list itselft. 毕竟,它们是两个不同的对象,其中unmodifiableList具有一个字段,即裸列表本身。

You need to make the "naked" list synchronized: 您需要使“裸”列表同步:

private List<Foo> list = Collections.synchronizedList(new ArrayList<Foo>());

But beware: that will only make sure the list internal state is coherent. 但是要当心:这只会确保列表内部状态是一致的。 As soon as you iterate on the list, you can't prevent a modification to the list to happen between two calls to the list iterator. 在列表上进行迭代后,就无法阻止对列表迭代器的两次调用之间对列表的修改。 So nothing will prevent a ConcurrentModificationException to happen in that case. 因此,在这种情况下,什么都不会阻止ConcurrentModificationException发生。 To prevent that, you should not return any reference (even an indirect one) to the list. 为避免这种情况,您不应将任何引用(甚至是间接引用)返回到列表。 All modifications and iterations to the list should be encapsulated in your class, and properly synchronized. 对列表的所有修改和迭代都应封装在您的类中,并正确同步。

You can return an unmodifiable-clone of original list to the caller. 您可以将原始列表的不可复制克隆返回给调用方。 The disadvantage is that the caller may end up with a "stale" version of the list. 缺点是呼叫者可能最终得到列表的“陈旧”版本。 However, by this way you achieve safe iterations. 但是,通过这种方式可以实现安全的迭代。 In concurrent world, it is OK to return last successfully updated data to the caller. 在并发世界中,可以将最后成功更新的数据返回给调用方。

public List<Thing> getThings() {
  List<Thing> copytOfThings = new ArrayList<>();
  copyOfThings.addAll(_things); //original list items.
  return Collections.unmodifiableList(copyOfThings);
}

There are a couple of ways you could do this: 您可以通过以下两种方法执行此操作:

  1. Return a copy of the list, rather than an unmodifiable view of it 返回列表的副本,而不是其不可修改的视图
  2. Rather than using the iterator, use List.get(int) 与其使用迭代器,不如使用List.get(int)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM