2

今日、私は を使用して 1 つのタイムアウト ジョブを作成していましたが、変数 TimerTaskがあるという新しい問題に陥りました。私の理解では、この変数の値が変更されるとすぐに、実行中のすべてによって通知されます。しかし、このプログラムを実行すると、許容できない出力を下回りました。static volatile booleanflagthread

O/P:

--------------
--------------
DD
BB
Exiting process..
CC

私の最後の印刷は終了プロセスであるはずです..なぜこの奇妙な動作なのですか?

私のコードは次のとおりです。

public class TimeOutSort {

    static volatile boolean flag = false;

    public static void main(String[] args) {

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {

            @Override
            public void run() {

                flag = true;
                System.out.println("Exiting process..");
                // System.exit(0);
            }
        }, 10 * 200);

        new Thread(new Runnable() {

            @Override
            public void run() {
                while (!flag)
                    System.out.println("BB");

            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                while (!flag)
                    System.out.println("CC");

            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                while (!flag)
                    System.out.println("DD");

            }
        }).start();
    }

}

編集:どうすればこれを達成できますか?

4

6 に答える 6

3

volatileスレッドが変数にアクセスするたびに、各スレッドに表示されるバージョンを使用する必要があることを意味します(つまり、スレッドごとのキャッシュはありません)。

これは、がに設定された直後にCC印刷スレッドが実際に実行されるように強制するものではありません。CC印刷スレッドが実行される前に、1つのスレッドがフラグ設定してメッセージを印刷することは(特にシングルコアマシンでは)完全に可能です。flagtrue

また、toの印刷には、テストコードのマルチスレッド動作を変更する可能性のあるロック(呼び出しSystem.out内のどこか)の取得が含まれることに注意してください。println()

于 2012-07-26T13:41:14.203 に答える
3

スレッドは任意の順序でコードを実行できます

thread BB: while (!flag) // as flag is false
thread Main:   flag = true;
thread Main:   System.out.println("Exiting process..");
thread BB:     System.out.println("BB");

私の期待は、最後の印刷が終了プロセスになるはずです..

スレッドは、同時に独立して実行されるように設計されています。フラグを設定したときに各スレッドがどこにあるかわからないため、これが常に最後のステートメントであるとしたら驚くでしょう。

于 2012-07-26T13:42:12.463 に答える
1

「CC」を出力するスレッドは、「Exiting process ...」を出力するスレッドがそれを出力するまで、CPU時間を受信しませんでした。これは予想される動作です。

于 2012-07-26T13:40:32.447 に答える
1

揮発性ではありません (そうでない場合、一部のスレッドは停止しませんでした)。これは、さまざまなスレッドでの命令の実行順序に関するものであり、中間ステップでループを明示的に同期しない限り、これはランダムです (OS のスケジューリングに依存します)。

于 2012-07-26T13:42:12.880 に答える
1

得られた説明に別の言い回しを追加するには: サンプル出力では、出力するスレッドが(どこかで)行との間で"CC"中断されました。つまり、ウェイクアップ後、フラグの次のチェックのに実行されます。(フラグの値を変更したからというだけではなく、他のスレッドがそのタイム スライスをブロックしたり、使い果たしたりしたために、起動されることもありません。)while (!flag)System.out.println()println()

于 2012-07-26T13:46:56.433 に答える
0

私はそれをテストしませんでしたが、あなたはこのようにそれを達成するかもしれません

public class TimeOutSort {

static volatile boolean flag = false;

public static void main(String[] args) {

    Timer timer = new Timer();
    timer.schedule(new TimerTask() {

        @Override
        public void run() {

            synchronized(flag){
                 flag = true;
                 notifyAll();
            }


        }
    }, 10 * 200);

    new Thread(new Runnable() {

        @Override
        public void run() {

            synchronized(flag){
                if(!flag)
                {
                    wait();
                }
                System.out.println("BB");

            }


        }
    }).start();

    new Thread(new Runnable() {

        @Override
        public void run() {

              synchronized(flag){
                if(!flag)
                {
                    wait();
                }
                System.out.println("CC");

            }
        }
    }).start();

    new Thread(new Runnable() {

        @Override
        public void run() {

              synchronized(flag){
                if(!flag)
                {
                    wait();
                }
                System.out.println("DD");

            }


        }
    }).start();
}

}

于 2015-02-01T16:55:34.563 に答える