2

ArrayListさまざまなスレッドによって頻繁に照会および変更されるトランザクション情報オブジェクトを含む Java クラスがあります。基本レベルでは、クラスの構造は次のようになります (現在、同期は存在しません)。

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 操作に基づいて、かなりスケーラブルな実装です。

コードに必要な 1 つの変更は、ConcurrentLinkedQueue が List インターフェースを実装しないことであり、Iterable または Queue タイプのいずれかに従う必要があります。実際に失われる唯一の操作は、インデックスを介したランダム アクセスですが、それがアクセス パターンの問題であるとは思いません。

于 2013-05-13T20:38:58.620 に答える