4

アプリケーションで複数のスレッドを使用しています。基本的に私はコンボボックスを持っており、受信トレイを選択するとp1が再開してp2が一時停止し、送信を選択するとp2が開始してp1が停止します。以下はコードです(私はそれが完璧ではないと確信しています)

public void modifyText(ModifyEvent e) {
                if (combo.getText().equals("Inbox"))
                {
                    synchronized(p2) 
                    {
                        p2.cont = false;
                    }
                    table.removeAll();
                    synchronized(p1)
                    {
                        p1.cont = true;
                        p1.notify();
                    }
                }


                else if (combo.getText().equals("Sent"))
                {
                    synchronized(p2) 
                    {
                        p1.cont = false;
                    }
                    table.removeAll();
                    synchronized(p1)
                    {
                        p2.cont = true;
                        p2.notify();
                    }
                }
            }
        });

P1とP2の場合、whileループ内にこれがあります。

synchronized (this) {
            while (cont == false)
                try {
                    wait();
                } catch (Exception e) {
                }
        } 

...そのままで動作しています(私はスレッドの初心者です)。コンボボックスで[送信済み]を押すと、IllegalStateMonitorExceptionが発生します。誰かが私が問題plzを解決するのを手伝ってもらえますか?

よろしくお願いいたします。Krt_Malta

4

3 に答える 3

6

問題はここにあります:

synchronized(p1)
{
    p2.cont = true;
    p2.notify();
}

p2.notify()ロックがオンになっていないときに実行しています(p2通知を呼び出すには、モニターを保持する必要があります)。に変更synchronized(p1)synchronized(p2)ます。さらに、他の同期された句も逆にする必要がありますが、これも誤りです。したがって、例として:

synchronized(p1) 
{
    p1.cont = false;
    // p1.notify(); <- do you need this here?
}
table.removeAll();
synchronized(p2)
{
    p2.cont = true;
    p2.notify();
}

さらに、他のコードも少し間違っています。ループ全体をロックして、もう少しアトミックにするのは非常に悪い習慣です。

while (!cont) {
    synchronized (this) {
       try {
           wait();
       } catch (Exception e) {
       }
    }
}

synchronised追加の最適化、可能であれば避けてください:

if (p1.cont) {
   synchronized(p1) 
   {
       p1.cont = false;
       // p1.notify(); <- do you need this here?
   }
}
table.removeAll();

if (!p2.cont) {
   synchronized(p2)
   {
       p2.cont = true;
       p2.notify();
   }
}

ここでcontフィールドをvolatile作成し、必要に応じてifステートメントの他の部分をミラーリングします。

編集:これを振り返り、私が最近直面した並行性のバグと戦うと、このパターンを実装する人は、ロックされているオブジェクトとハーフロックされているオブジェクトがwhileの条件で見られている場合、無限の待機の問題に直面する可能性がありますループ(これは、条件付きの評価と待機ステートメントの強制の間に状態が変化する可能性があるギャップがあるためです)。この場合、同期ブロックをループの外側に配置します。

于 2010-03-16T18:01:59.823 に答える
0

このコードでは

                synchronized(p1)
                {
                    p2.cont = true;
                    p2.notify();
                }

同期してp1いますが、を呼び出しnotify()p2います。これにより、例外が発生します。

于 2010-03-16T18:02:43.257 に答える
-1

awtイベントディスパッチスレッドで待つことはできません。そうしないと、アプリ全体が停止します。http://en.wikipedia.org/wiki/Event_dispatching_threadについて読む

また、自分が何をしているのかを本当に理解していない限り、生のスレッドを使用しないでください。http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-summary.htmlをチェックして、 Executorsを読んでください。

于 2010-03-16T18:04:59.733 に答える