0

私のアプリケーションには、1 つのテキスト フィールドと 1 つのボタンがあります。テキストフィールドからフォーカスが失われた後、最初のスイングワーカー (sw1 と仮定します) が呼び出されます。これにより、ポップアップが開き、テキスト フィールドに入力する値が入力されます。ユーザーがボタンをクリックすると、2 番目の swing ワーカー (sw2 と仮定します) が呼び出されます。問題は、テキスト フィールドに何かを書き込んでボタンをクリックすると、最初に sw1 が開始されてテキスト フィールドに入力する値が計算され、同時に sw2 も開始されるということです。そして、sw2 が最初に終了し、次に sw1 が結果を取り込みます。私が望むのは、sw2 が sw1 の終了を待つことです。sw1 がタスクを完了すると、sw2 に通知します。インターネットとスタックオーバーフローで非常に多くの参考文献を参照しました。これは私の要件にほぼ一致するものです。sw1を開始するクラス内に静的最終オブジェクトを作成しようとしました:

public final static Object lockObject = new Object();

次に、sw1 の done() メソッド内に、次のようなコードを記述しました。

synchronized(lockObject) {
        sw1.notifyAll();
}

2 番目のクラスの doInBackground() メソッド内の最初の行に、次のようなコードを記述しました。

synchronized(FirstClass.lockObject) {
    try {
        sw2.wait();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

しかし、java.lang.Object.notifyAll(Native Method) で java.lang.IllegalMonitorStateException を取得しています。何が問題なのか、どうすれば私が望むように動作させることができるのか、誰か教えてもらえますか?

更新:アーネストのソリューションに従って、コードを変更したところ、次のようになりました。

    FirstClass.java

    public final static Object lockObject = new Object();

    public static boolean flag = false;

    someMethod() {
        synchronized(lockObject){
            sw1.doInbackground() {
            ......
            }

            sw1.done() {
            .....
            flag = true;
            lockObject.notifyAll();
            }

        }
    }


    SecondClass.java

    anotherMethod() {
        sw2.doInbackground() {
            try {
                while (!FirstClass.flag) {
                    FirstClass.lockObject.wait();
                }
                FirstClass.flag = false;
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            ......
        }

    }

しかし、まだ lockObject.notifyAll() 行で java.lang.IllegalMonitorStateException を取得しています。私がそれを正しく行っているかどうか教えてください。

ありがとう。

4

3 に答える 3

2

このような単純な同期機能を作り直す必要はありません。たとえば、CountDownLatchを使用できます。Sw1はカウントダウンを行い、sw2-待機します。

于 2012-07-13T15:40:28.243 に答える
2

コードは次のようになります。

FirstClass.java

public final static Object lockObject = new Object();

public static boolean flag = false;

someMethod() {
    sw1.doInbackground() {
    ......
    }

    sw1.done() {
    .....
    }

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


SecondClass.java

anotherMethod() {
    sw2.doInbackground() {
        try {
            synchronized(lockObject){
                while (!FirstClass.flag) {
                    FirstClass.lockObject.wait();
                }
                FirstClass.flag = false;
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        ......
    }

}

しかし。FirstClass.java と SecondClass.java のインスタンスが複数ある場合、グローバルな静的オブジェクトで同期すると問題が発生します。オブジェクトインスタンスを渡す方法を実際に見つける必要があります。

あなたのユースケースを正しく理解していれば、ユーザーがフィールドの編集を開始したときに sw2 のボタンを無効にし、最初のワーカーが終了したときに再度有効にすることはできませんか? ユーザーにとっても、はるかに明確になります。

于 2012-07-13T15:40:04.413 に答える
1

wait()およびを呼び出すことができるのはnotify()、モニターを保持しているオブジェクトに対してのみです。各コード スニペットでは、1 つのオブジェクトをロックしていますが、これらのメソッドを別のオブジェクトで呼び出しています。それはそのようには機能しません。残念ながら、あなたが何をしようとしているのかわからないので、特定の修正を与えるのは難しいですが、基本的に、これらのブロックは次のようになる必要があります

synchronized(sw2) {
    try {
        sw2.wait();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

T1 と T2 の 2 つのスレッドがあり、オブジェクト O1 があるとします。次に、スレッド T1 で実行されているコードが、スレッド T2 のコードが続行しても問題ないと判断するまで待ちたい場合は、オブジェクトO1で同期してから を呼び出す必要がありますO1.wait()。T2 で実行されているコードがそのメッセージを T1 に送信したい場合、同期して(または.)O1を呼び出す必要があります。O1.notify()O1.notifyAll()O1

于 2012-07-13T13:52:11.727 に答える