【问题标题】:How to handle synchronization of frequent concurrent read/writes on a Java ArrayList如何处理 Java ArrayList 上频繁并发读/写的同步
【发布时间】:2013-05-13 19:14:55
【问题描述】:

我有一个 Java 类,其中包含一个 ArrayList 的事务信息对象,这些对象经常被不同的线程查询和修改。在基本层面上,类的结构看起来像这样(目前不存在同步):

class Statistics
{
    private List<TranInfo> tranInfoList = new ArrayList<TranInfo>();

    // This method runs frequently - every time a transaction comes in.
    void add(TranInfo tranInfo)
    {
        tranInfoList.add(tranInfo);
    }

    // This method acts like a cleaner and runs occasionally.       
    void removeBasedOnSomeCondition()
    {
        // Some code to determine which items to remove

        tranInfoList.removeAll(listOfUnwantedTranInfos);
    }

    // Methods to query stats on the tran info.
    // These methods are called frequently.
    Stats getStatsBasedOnSomeCondition()
    {
        // Iterate over the list of tran info
        // objects and return some stats
    }


    Stats getStatsBasedOnSomeOtherCondition()
    {
        // Iterate over the list of tran info
        // objects and return some stats
    }
}

我需要确保列表上的读/写操作正确同步,但是,性能非常重要,所以我不想最终锁定每个方法调用(尤其是并发读操作)。我查看了以下解决方案:

CopyOnWriteArrayList

我查看了使用 CopyOnWriteArrayList 来防止在迭代列表时修改列表时引发 ConcurrentModificationExceptions;这里的问题是每次修改列表时都需要复制...考虑到列表的修改频率和列表的潜在大小,这似乎太昂贵了。

读写锁

ReadWriteLock 可用于同步读/写操作,同时允许发生并发读操作。虽然这种方法可行,但最终会导致类中出现大量同步代码(但这并不是世界末日)。


有没有其他聪明的方法来实现这种同步而不会造成很大的性能损失,或者上述方法之一是推荐的方法吗?对此的任何建议将不胜感激。

【问题讨论】:

  • 列表的修改频率如何?有多大?
  • ReadWriteLock 是 IMO 的正确解决方案。如果混合的问题让您感到困扰,请插入一个代理级别。
  • 你知道这是个问题吗,因为我不认为你经常调用这些方法会导致问题。即是 1K/s、10K/s、100K/s 还是 1M/s?
  • 如果您不想锁定每个方法调用,并且不想在每次写入时复制整个列表,则需要放弃对List 的随机排序访问。也许是ConcurrentLinkedQueue
  • 看来你已经超出了ArrayList的设计意图。也许您应该考虑另一个更专业的容器。这听起来像是并发队列或同步列表的工作。你看过那些吗?

标签: java concurrency arraylist


【解决方案1】:

我会使用Collections.synchronizedList(),直到您确定它确实是您的应用程序的关键性能瓶颈(不用说我怀疑它是;-))。您只能通过彻底的测试才能确定。我假设您知道“过早优化”...

如果您努力优化对该列表的访问,我会说ReadWriteLock 是一个好方法。

【讨论】:

    【解决方案2】:

    另一个可能有意义的解决方案(尤其是在读/写繁重的情况下)是 ConcurrentLinkedQueue (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html)。基于 CAS 操作,它是一个在竞争中具有相当可扩展性的实现。

    您的代码需要进行的一项更改是 ConcurrentLinkedQueue 没有实现 List 接口,您需要遵守 Iterable 或 Queue 类型。您真正丢失的唯一操作是通过索引进行随机访问,但我认为这不是您的访问模式中的问题。

    【讨论】:

      猜你喜欢
      • 2012-08-05
      • 2014-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-08
      • 1970-01-01
      • 2012-08-13
      • 2012-03-02
      相关资源
      最近更新 更多