【问题标题】:Returning Java Arrays vs Collections返回 Java 数组与集合
【发布时间】:2011-03-23 18:56:41
【问题描述】:

我正在尝试考虑一些关于 Java 应用程序中的内存分配和多线程的设计,这就是我想知道的:

我有一个具有同步集合的类,例如一个每秒更新几次的列表,但所有更新都发生在该类及其自己的线程中,而不是来自其他线程。但是,我有许多其他线程调用 getCollection() 方法并执行 foreach 以只读方式迭代其内容。这是我不知道的:

如果另一个线程正在迭代同步集合,执行更新的单个线程是否必须等到没有其他线程正在迭代的时间点?

我的第二个问题是,通过执行 .toArray 返回集合的数组副本而不是集合本身似乎是有意义的,但是从内存的角度考虑它不会必须分配一个新的数组是每次集合内容的大小,如果在包含数千个对象的集合上每秒被调用数百次,我不知道这是否有意义。

另外,如果我从不返回集合本身,那么不再需要使列表同步?

不胜感激。谢谢! - 邓肯

【问题讨论】:

    标签: java multithreading arrays memory collections


    【解决方案1】:

    如果另一个线程正在迭代 同步收集将单 执行更新的线程有 等到没有的时间点 其他线程在迭代吗?

    如果您在谈论同步(非并发)集合,那么可以。 至于第二个问题, 看起来像是 java.util.concurrent.CopyOnWriteArrayList 的真实用例。

    【讨论】:

      【解决方案2】:

      我建议您使用 CopyOnWriteArrayList。这是线程安全的,并且可以被任意数量的线程高效地读取访问。如果您有少量更新,这应该没问题。

      但是,回答您的问题。如果您在修改同步集合时对其进行迭代,您将收到 ConcurrentModificationException(COWAL 没有收到此信息)您的更新不会被此阻止,只有您的读者会遇到问题。

      不是每次调用 getCollection 时创建一个副本,而是在每次修改集合时创建一个副本(远不经常)这就是 COWAL 为您所做的。

      如果您按需返回副本,您仍需要同步集合。

      【讨论】:

        【解决方案3】:

        可能最简单的处理方法是保留两个集合:一个由类本身更新,另一个是在调用getCollection() 时返回的 volatile 字段中的只读副本。

        后者需要在适当时由更新主集合的进程重新创建。这允许您以原子方式更新您的集合:一次更改多个元素,同时隐藏中间状态。

        如果您的更新不频繁并且每次更新都使集合处于一致状态,则使用已建议的 CopyOnWriteArrayList。

        【讨论】:

          【解决方案4】:

          似乎集合被频繁更新并且#getCollection() 被频繁调用。您可以使用 CopyOnWriteArrayList,但每次修改数组时都会创建一个副本。所以你需要看看这对性能有何影响。

          另一种选择是在每次调用#getCollection 时让类中的线程生成副本。这将涉及#getCollection 等待内部类线程完成。

          如果您只希望#getCollection 返回最近的副本而不是最新的副本,那么您可以让内部线程定期创建在#getCollection 中返回的集合的副本。副本需要是 volatile 或 AtomicReference。

          【讨论】:

            猜你喜欢
            • 2016-03-29
            • 1970-01-01
            • 2020-01-05
            • 2012-08-30
            • 1970-01-01
            • 2014-01-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多