16

マルチスレッド システムでの Queue の実装に関して、いくつかの驚きを経験してきました。ここは:-

シナリオ:- 1 つのプロデューサー、1 つのコンシューマー:- プロデューサーが整数をキューに入れます。コンシューマーは単にキューからそれを削除します。

キューの基礎となるデータ構造:- TreeSet (使用するとは考えていませんでした)、LinkedList、LinkedBlockingQueue (サイズは不定)

コード:- キューとしての TreeSet:-

while (i < 2000000) {
        synchronized (objQueue) {

            if (!(objQueue.size() > 0)) {
                try {
                    objQueue.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            Integer x = objQueue.first();
            if (x != null) {
                objQueue.remove(x);
                ++i;
            }
        }
    }

編集:-

      while (i < 2000000) {
        synchronized (objQueue) {
            objQueue.add(i);
            ++i;
            objQueue.notify();
        }
    }

LinkedBlockingQueue の場合:-

     while (i < 2000000){
        try {
            objQueue.put(i);
            ++i;
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            Thread.currentThread().interrupt();
        }
    }

      while (i < 2000000) {
        try {
            objQueue.take();
            ++i;

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            Thread.currentThread().interrupt();
        }
    }

LinkedList の場合:- synchronized と同様のコード。

質問:-

1) Visual VM を介してパフォーマンスを測定したところ、プロデューサー コードの場合、O(log n) 時間かかるにもかかわらず、TreeSet が LinkedBlockingQueue および LinkedList よりもパフォーマンスが優れていることがわかりました。Linked 構造でのオブジェクトの作成は、大きなオーバーヘッドです。 . 理論と実践がまったく異なるのはなぜですか?キューの実装でツリー構造よりもリンクされた配列構造を好むのはなぜですか?

2) TreeSet は LinkedBlockingQueue よりもパフォーマンスが優れている LinkedList よりも優れたパフォーマンスを発揮したため、同期は ReeentrantLock に対して明確な勝者として出てきます。Visual VM の結果を添付できればと思います。記事の投票ではありませんhttp://www.ibm.com/developerworks/java/library/j-jtp10264/index.html

操作は

Dell Vostro 1015、core 2 duo 2.10、2 GB RAM、32 ビット オペレーティング システム、および

JVM: Java HotSpot(TM) Client VM (20.1-b02、混合モード) Java: バージョン 1.6.0_26、ベンダー Sun Microsystems Inc.

4

3 に答える 3

22

1. リンクされたリストをトラバースし、次のノードをロックしてから現在のノードのロックを解除するスレッドReentrantLockを実装する必要がある場合は、より使いやすいかもしれません。

2. Synchronizedキーワードは、ロックの粗大化などの状況に適しており、アダプティブ スピニング、バイアス ロック、およびエスケープ解析によるロック省略の可能性を提供します。これらの最適化は、現在 ReentrantLock には実装されていません。

適切なパフォーマンスの比較については、次を参照してください。

https://blogs.oracle.com/dave/javautilconcurrent-reentrantlock-vs-synchronized-which-should-you-use

于 2012-07-22T13:16:05.030 に答える
5
  1. ベンチマークに欠陥があるため: 実際のユースケースでは、要素をキューに追加およびキューから削除するのにかかる時間よりも、キューから要素を生成および消費するのにかかる時間の方がはるかに重要です。したがって、キューの生のパフォーマンスはそれほど重要ではありません。ところで、コードは最初のキュー実装から要素を取得する方法のみを示しており、要素を追加する方法は示していません。さらに、適切な構造の選択は、パフォーマンスではなく動作に基づいて行われます。並行処理が必要な場合は、ブロック キューを選択します。これは、ブロック キューが実装されており、コードのようなバグがないためです。FIFO が必要な場合 (多くの場合、これが必要です)、TreeSet を選択しません。

  2. 同期と ReentrantLock を比較したい場合は、一方に 1 つのデータ構造を使用し、もう一方に別のデータ構造を使用しないでください。以前は ReentrantLock の方が高速でしたが、現在は同じレベルです (Brian Goetz が JCIP で言っていることを信じるなら)。とにかく、安全性/機能上の理由から、どちらかを選択します。パフォーマンス上の理由ではありません。

于 2012-07-22T13:25:15.257 に答える