0

みんな!

InAndOutを拡張するクラス ( ) を作成しましたThread。このクラスは、コンストラクターで 2 つLinkedConcurrentQueueentranceとを受け取りexit、メソッドはオブジェクトを からにrun転送します。entranceexit

私の主な方法では、それぞれにいくつかの値を持つ2 つLinkedConcurrentQueuemyQueue1とをインスタンス化しました。myQueue2次に、2 つの InAndOut をインスタンス化しました。1 つはmyQueue1(入口) とmyQueue2(出口) を受け取り、もう 1 つは (入口)myQueue2と(出口) を受け取りmyQueue1ます。次に、両方のインスタンスの start メソッドを呼び出します。

その結果、いくつかの反復の後、すべてのオブジェクトがキューから別のキューに転送されます。つまり、myQueue1空になり、myQueue2すべてのオブジェクトが「盗まれます」。しかし、各反復 (100 ミリ秒など) でスリープ コールを追加すると、動作は期待どおりになります (両方のキューの要素番号間の平衡)。

なぜそれが起こっているのか、それを修正する方法は?run メソッドでこのスリープ呼び出しを使用しない方法はありますか? 私は何か間違ったことをしていますか?

ここに私のソースコードがあります:

import java.util.concurrent.ConcurrentLinkedQueue;

class InAndOut extends Thread {

    ConcurrentLinkedQueue<String> entrance;
    ConcurrentLinkedQueue<String> exit;
    String name;

    public InAndOut(String name, ConcurrentLinkedQueue<String> entrance, ConcurrentLinkedQueue<String> exit){
        this.entrance = entrance;
        this.exit = exit;
        this.name = name;
    }

    public void run() {
        int it = 0;
        while(it < 3000){
            String value = entrance.poll();

            if(value != null){
                exit.offer(value);
                System.err.println(this.name + " / entrance: " + entrance.size() + " / exit: " + exit.size());
            }

            //THIS IS THE SLEEP CALL THAT MAKES THE CODE WORK AS EXPECTED
            try{
                this.sleep(100);
            } catch (Exception ex){

            }
            it++;
        }
    }
}

public class Main {

    public static void main(String[] args) {

        ConcurrentLinkedQueue<String> myQueue1 = new ConcurrentLinkedQueue<String>();
        ConcurrentLinkedQueue<String> myQueue2 = new ConcurrentLinkedQueue<String>();

        myQueue1.offer("a");
        myQueue1.offer("b");
        myQueue1.offer("c");
        myQueue1.offer("d");
        myQueue1.offer("e");
        myQueue1.offer("f");
        myQueue1.offer("g");
        myQueue1.offer("h");
        myQueue1.offer("i");
        myQueue1.offer("j");
        myQueue1.offer("k");
        myQueue1.offer("l");

        myQueue2.offer("m");
        myQueue2.offer("n");
        myQueue2.offer("o");
        myQueue2.offer("p");
        myQueue2.offer("q");
        myQueue2.offer("r");
        myQueue2.offer("s");
        myQueue2.offer("t");
        myQueue2.offer("u");
        myQueue2.offer("v");
        myQueue2.offer("w");

        InAndOut es = new InAndOut("First", myQueue1, myQueue2);
        InAndOut es2 = new InAndOut("Second", myQueue2, myQueue1);

        es.start();
        es2.start();
    }
}

前もって感謝します!

4

3 に答える 3

1

スレッドのスケジューリングが決定論的であったとしても、観測された動作はもっともらしいままでした。両方のスレッドが同じタスクを実行する限り、信頼することはできませんが、バランスが取れている可能性があります。しかし、1 つのキューが空になるとすぐに、タスクのバランスが取れなくなります。比較:

  1. スレッド 1 は、アイテムを持つキューからポーリングします。このpollメソッドは、削除を反映するようにソース キューの状態を変更します。コードは、受信したアイテムを他のキューに挿入し、内部リスト ノード オブジェクトを作成し、挿入を反映するようにターゲット キューの状態を変更します。すべての変更は、他のスレッドから見える方法で実行されます。

  2. 空のキューから 2 つのポーリングをスレッド化します。メソッドはpoll参照をチェックして見つけnullます。それだけです。他のアクションは実行されません。

1 つのキューが空になると、1 つのスレッドが他のスレッドよりもはるかに多くのことを行うことは明らかだと思います。より正確には、1 つのスレッドが 3000 回のループ反復 (300000 回も実行できる) を完了することができますが、これは、もう一方のスレッドが 1 回の反復を実行するのに十分ではありません。

したがって、1 つのキューが空になると、1 つのスレッドがほぼ即座にループを終了し、その後、もう 1 つのスレッドがすべてのアイテムを 1 つのキューから別のキューに転送し、その後も終了します。

そのため、ほぼ決定論的なスケジューリング動作であっても、1 つのキューがたまたま空になると、バランスは常に傾くリスクを負います。


キューにはるかに多くの項目を追加して、1 つのキューが空になる可能性を減らすことで、バランスの取れた実行の可能性を高めることができます。反復回数を (100 万をはるかに超えるまで) 上げて、キューが空になったときにスレッドがすぐに終了するのを回避したり、nullアイテム以外が表示された場合にのみカウンターをインクリメントしたりできます。CountDownLatchを使用して、ループに入る前に両方のスレッドを待機させ、スレッドの起動オーバーヘッドを補正して、可能な限り同期して実行することができます。


ただし、依然として非決定論的であり、ポーリング ループが CPU リソースを浪費することに注意してください。ボット 試して学習しても大丈夫です。

于 2013-11-11T22:15:07.467 に答える
0

スレッドの実行順序は定義されていないため、何が起こる可能性があります。ただし、両方のスレッドを同時に開始するわけではないため、何が起こるかについていくつかの仮定を立てることができます。

  1. es が最初に開始されるため、CPU が十分に高速な場合、es2 の開始前にキュー 1 からキュー 2 にすべてがプッシュされ、テイク時にスリープ状態になります。
  2. es2 が起動し、1 つの要素を queue2 から queue1 に戻します。
  3. es は同時にウェイクアップし、要素を元に戻します。

両方のスレッドが「ほぼ」同じ速度で動作する必要があるため、1 つの可能性のある結果は、 に要素が 1 つしかないかまったくなくes、 に残りのすべての要素があるということですes2

于 2013-11-11T19:31:23.070 に答える