0

このプログラムの望ましい出力は次のとおりです。

ピンポン ピンポン ピンポン

それでも、それと

ポンピンなど

問題は、Ping スレッドを作成して最初に実行することです。そのため、ポンが時折最初に来る理由がわかりません。

これが私のコードです(すぐにコンパイルできます)。それは本質的に機能します。「Pong」が最初に表示されることがある理由がわかりません。なぜこれが起こっているのか、誰かが光を当てることができますか?

// Printer class - will be the object that both threads lock / synchronize onto
class Printer
{
    int numberOfMessages;
    int messageCount;

    // Constructor allowing user to choose how many messages are displayed
    Printer(int numberOfMessages)
    {       
        this.numberOfMessages = numberOfMessages;
        this.messageCount = 0;
    }

    // If more messages are to be printed, print and increment messageCount
    void printMsg(String msg)
    {
        if (messageCount < numberOfMessages)
        {
            System.out.println("[" + msg + "]");            
            ++messageCount;
        }
        else
        {
            System.exit(0);
        }
    }
}

// PingPong thread
class PingPongThread extends Thread
{
    Printer printer;
    String message; 

    public PingPongThread(Printer printer, String message)
    {
        this.printer = printer;
        this.message = message;
        this.start();
    }

    @Override
    public void run()
    {
        while(true)
        {
            synchronized (printer)
            {                   
                // Print message whether it is Ping or Pong
                printer.printMsg(message);

                // Notify
                printer.notify();

                // Wait
                try
                {
                    printer.wait();
                } 
                catch (InterruptedException e)
                {               
                    e.printStackTrace();
                }
            }
        }
    }


}

// Two threads communicate with eachother to alteratively print out "Ping" and "Pong"
public class PingPong
{
    public static void main(String args[])
    {
        Printer printer = new Printer(6);

        PingPongThread pingThread = new PingPongThread(printer, "Ping");
        PingPongThread pongThread = new PingPongThread(printer, "Pong");
    }
}
4

6 に答える 6

1

メソッドは別のスレッドで実行されるためrun、適切な同期がない限り、どのスレッドが最初に実行されるかを推測できません。スレッドが最初に開始されたとしても、それがより重要になるという意味ではありません。すべての動物は平等です。

スレッドの開始時に通知される特別なフラグをスレッドに作成する必要があります。そして、2 番目のスレッドを開始する前にフラグを待ちます。それを行う簡単な方法は、を使用することConditionです。

于 2013-04-04T09:30:54.397 に答える
1

と などの 2 つのスレッドを作成t1t2、次を呼び出すとします。

t1.start();
t2.start();

t1が の前に実行を開始するという意味ではありませんt2t2可能性はありますが、最初に開始される可能性があります。保証人が最初に開始する独自のアプローチを作成する必要がありますt1。たとえばwait()、オブジェクトで最初のスレッドを開始した後notify()、そのオブジェクトの最初のスレッドでrun()

于 2013-04-04T09:35:42.617 に答える
1

これ

    Printer printer = new Printer(6);
    PingPongThread pingThread = new PingPongThread(printer, "Ping");
    synchronized (printer) {
        printer.wait();
    }
    PingPongThread pongThread = new PingPongThread(printer, "Pong");

pingThread が常に最初に開始されることを保証します。

それにもかかわらず、スレッドの調整は、誰がより速く実行するかによって異なります。このことを考慮

final Object obj = new Object();
Thread t1 = new Thread() {
    public void run() {
        synchronized (obj) {
            obj.notify();
        }
    };
};

Thread t2 = new Thread() {
    public void run() {
        synchronized (obj) {
            try {
                obj.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
};

t1.start();
t2.start();

t2 が待機する前に t1 が通知すると、テストはハングします。

于 2013-04-04T09:36:39.417 に答える
1

スレッドの実行順序を強制したい。JVM はそれを保証しないため、独自に作成する必要があります。私は2つの解決策を考えることができます。

醜いハックですが、動作する可能性があります: 最初のスレッドを開始した後、2 番目のスレッドを開始する前に現在のスレッドを生成して、実行を「奨励」します。例えば:

PingPongThread pingThread = new PingPongThread(printer, "Ping");
Thread.yield();
PingPongThread pongThread = new PingPongThread(printer, "Pong");

これは最も簡単な解決策ですが、たとえば、別のスレッド (たとえば、イベント ハンドラー) が yield 後にコントロールを取得する場合など、毎回動作するとは限りません。

より堅牢なアプローチ: 2 番目のスレッドを開始する前に、メイン スレッドが他のシグナルを待機するようにします。このシグナルが という名前のフィールドを通過するとするとlock、次のようになります。

Object lock = new Object();
PingPongThread pingThread = new PingPongThread(lock, printer, "Ping");
lock.wait();
PingPongThread pongThread = new PingPongThread(lock, printer, "Pong");

スレッドrun()メソッドは次のようになります

synchronize (lock) { lock.notify(); }
while (true) {
  // As before...
}
于 2013-04-04T09:31:33.550 に答える
1

JVM は、スレッドが開始された順序で開始されることを保証しません。そのため、2 番目のスレッドが最初に開始されることがあります。

于 2013-04-04T09:31:46.533 に答える