Collections.unmodifiableList上的同步

时间:2015-07-06 14:43:37

标签: java multithreading synchronization thread-safety

我有一个问题。我想我知道答案,但出于某种原因,我更愿意在这里提出要求。

所以这是场景:

我有一个Object,它有一个列表作为字段。然后我有一个方法将列表作为unmodifiableList返回。

Oject类有其他方法可以向列表中添加元素。

因此,让我们设想一个案例,其中一个线程正在迭代不可修改的列表,另一个线程使用Object类方法将元素添加到列表中。

如何使这个线程安全?如果我同步unmodifiableList和列表itselft它会使它线程安全吗?毕竟它们是两个不同的对象,其中unmodifiableList有一个字段,它是裸列表itselft。

3 个答案:

答案 0 :(得分:4)

你需要制作"裸体" list synchronized:

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

但要注意:这只会确保列表内部状态是连贯的。只要迭代列表,就不能阻止在对列表迭代器的两次调用之间对列表进行修改。因此,在这种情况下,什么都不会阻止ConcurrentModificationException发生。为了防止这种情况,您不应该向列表返回任何引用(甚至是间接引用)。列表的所有修改和迭代都应封装在您的类中,并正确同步。

答案 1 :(得分:2)

您可以将原始列表的不可修改克隆返回给调用者。 缺点是呼叫者最终可能会失败。列表的版本。但是,通过这种方式,您可以实现安全的迭代。在并发世界中,可以将最后成功更新的数据返回给调用者。

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

答案 2 :(得分:0)

有几种方法可以做到这一点:

  1. 返回列表的副本,而不是不可修改的视图
  2. 使用List.get(int)
  3. 而不是使用迭代器