2

我有一个 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可用于同步读/写操作,同时允许发生并发读操作。虽然这种方法可行,但最终会导致类中出现大量同步代码(但这并不是世界末日)。


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

4

2 回答 2

3

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

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

于 2013-05-13T20:33:26.413 回答
0

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

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

于 2013-05-13T20:38:58.620 回答