55

授業の背後にある概念を理解するのに苦労していwait()ますObject。この質問のために、wait()notifyAll()Threadクラスにいるかどうかを検討してください。

class Reader extends Thread {
    Calculator c;
    public Reader(Calculator calc) {
        c = calc;
    }

    public void run() {
        synchronized(c) {                              //line 9
        try {
            System.out.println("Waiting for calculation...");
            c.wait();
        } catch (InterruptedException e) {}
            System.out.println("Total is: " + c.total);
        }
    }

    public static void main(String [] args) {
        Calculator calculator = new Calculator();
        new Reader(calculator).start();
        new Reader(calculator).start();
        new Reader(calculator).start();
        calculator.start();
    }
}

class Calculator extends Thread {
    int total;
    public void run() {
        synchronized(this) {                     //Line 31
            for(int i=0;i<100;i++) {
                total += i;
            }
             notifyAll();
        }
    } 
}

私の質問は、それがどのような違いを生んだかということです? 9 行目では、オブジェクト c のロックを取得してから、wait を使用する前にオブジェクトのロックを取得する必要があるという待機の条件を満たす待機を実行しています。31 行目で Calculator のオブジェクトのロックを取得した notifyAll の場合も同様です。 .

4

11 に答える 11

129

オブジェクトクラスにwait()を配置する背後にある概念を理解するのに苦労していますこの質問のために、wait()とnotifyAll()がスレッドクラスにあるかのように考えてください

Java 言語では、オブジェクトwait()の特定のインスタンス (Object正確には、そのオブジェクトに割り当てられたモニター) を使用します。特定のオブジェクト インスタンスを待機している 1 つのスレッドにシグナルを送信する場合はnotify()、そのオブジェクトを呼び出します。そのオブジェクト インスタンスを待機しているすべてのスレッドにシグナルを送信する場合は、notifyAll()そのオブジェクトで使用します。

wait()notify()が代わりにオンになっている場合Thread、各スレッドは他のすべてのスレッドのステータスを知る必要があります。スレッド 1 は、スレッド 2 が特定のリソースへのアクセスを待っていることをどのように知るのでしょうか? thread1 を呼び出す必要がある場合、それが待機thread2.notify()中であることをどうにかして確認する必要があります。thread2スレッドが必要なリソースまたはアクションを登録して、準備ができているか利用可能になったときに他のスレッドがシグナルを送ることができるメカニズムが必要です。

Java では、オブジェクト自体がスレッド間で共有されるエンティティであり、スレッド間の通信を可能にします。スレッドは相互に特定の知識を持たず、非同期で実行できます。それらは実行され、アクセスしたいオブジェクトをロックし、待機し、通知します。他のスレッドの知識はなく、ステータスを知る必要もありません。リソースを待機しているのはスレッド 2 であることを知る必要はありません。リソースについて通知するだけで、待機している人が誰であれ (存在する場合) 通知されます。

Java では、オブジェクトを同期、ミューテックス、およびスレッド間の通信ポイントとして使用します。オブジェクトを同期して、重要なコード ブロックへのミューテックス アクセスを取得し、メモリを同期します。何らかの条件が変化するのを待っている場合、つまり何らかのリソースが利用可能になるのを待っている場合は、オブジェクトを待ちます。スリープ状態のスレッドを目覚めさせたい場合は、オブジェクトに通知します。

// locks should be final objects so the object instance we are synchronizing on,
// never changes
private final Object lock = new Object();
...
// ensure that the thread has a mutex lock on some key code
synchronized (lock) {
    ...
    // i need to wait for other threads to finish with some resource
    // this releases the lock and waits on the associated monitor
    lock.wait();
    ...
    // i need to signal another thread that some state has changed and they can
    // awake and continue to run
    lock.notify();
}

プログラムにはいくつでもロック オブジェクトが存在する可能性があり、それぞれが特定のリソースまたはコード セグメントをロックします。100 個のロック オブジェクトと 4 つのスレッドしかない場合があります。スレッドがプログラムのさまざまな部分を実行すると、ロック オブジェクトの 1 つに排他的にアクセスできます。繰り返しになりますが、他のスレッドの実行ステータスを知る必要はありません。

これにより、ソフトウェアで実行されているスレッドの数を必要なだけ拡大または縮小できます。外部リソースで 4 つのスレッドがブロックしすぎていることがわかった場合は、数を増やすことができます。ボロボロのサーバーをプッシュしすぎて、実行中のスレッドの数を減らします。ロック オブジェクトは、実行中のスレッドの数に関係なく、スレッド間のミューテックスと通信を保証します。

于 2013-07-24T17:59:02.803 に答える
55

なぜwait()メソッドとnotify()メソッドがObjectクラスに属するのかをよりよく理解するために、実際の例を挙げましょう: ガソリンスタンドにトイレが1つあり、その鍵がサービスデスクに保管されているとします。トイレは、通りすがりのドライバーのための共有リソースです。この共有リソースを使用するには、見込みユーザーはトイレの鍵の鍵を取得する必要があります。利用者はサービスデスクに行き、鍵を受け取り、ドアを開けて内側から施錠し、施設を利用する。

一方、別の見込み客がガソリン スタンドに到着すると、トイレが施錠されているため利用できないことがわかります。彼はサービス デスクに行きますが、キーは現在のユーザーの手にあるため、そこにはありません。現在のユーザーが終了したら、ドアのロックを解除し、サービス デスクにキーを返します。彼は顧客を待つことを気にしません。サービスデスクは、待っている顧客にキーを渡します。トイレが施錠されている間に複数の見込み客が現れた場合、施錠の鍵を待つ列を形成する必要があります。各スレッドは、誰がトイレにいるかわかりません。

このアナロジーを Java に当てはめると、Java スレッドはユーザーであり、トイレはスレッドが実行したいコードのブロックです。Java は、synchronized キーワードを使用して現在実行中のスレッドのコードをロックし、それを使用したい他のスレッドを最初のスレッドが終了するまで待機させる方法を提供します。これらの他のスレッドは待機状態になります。スレッドを待機するためのキューがないため、Java はサービス ステーションほど公平ではありません。要求された順序に関係なく、待機中のスレッドのいずれかが次にモニターを取得する可能性があります。唯一の保証は、遅かれ早かれすべてのスレッドが監視対象のコードを使用できるようになることです。

最後に、あなたの質問への答え: ロックは、キー オブジェクトまたはサービス デスクである可能性があります。どれもスレッドではありません。

ただし、これらは現在、トイレがロックされているか開いているかを決定するオブジェクトです。これらは、バスルームが開いていることを通知 (「通知」) したり、ロックされているときに待機するように人々に依頼したりする位置にあるオブジェクトです。

于 2015-09-03T16:44:34.050 に答える
4

最初の質問への答えは、Java のすべてのオブジェクトには 1 つのみがlock(monitor)ありwait(),notify(),notifyAll()、モニターの共有に使用されるため、それらがObjectクラスではなくクラスの一部である理由Threadです。

于 2013-07-24T17:02:49.230 に答える
0

これらのメソッドはロックで機能し、ロックはスレッドではなくオブジェクトに関連付けられています。したがって、それは Object クラスにあります。

メソッドwait()、notify()、notifyAll()は単なるメソッドではなく、同期ユーティリティであり、Javaのスレッド間の通信メカニズムで使用されます。

詳細な説明については、http: //parameshk.blogspot.in/2013/11/why-wait-notify-and-notifyall-methods.htmlを参照してください。

于 2013-11-20T21:14:52.813 に答える
-1

このwait()メソッドは、指定されたオブジェクトのロックを解放し、ロックを取得できるようになるまで待機します。

notify()notifyAll()オブジェクトのロックを取得するために待機しているスレッドがあるかどうかを確認し、可能であればそれらにロックを与えます。

ロックがオブジェクトの一部である理由は、リソース (RAM) がObjectではなくによって定義されているためThreadです。

これを理解する最も簡単な方法は、スレッドはオブジェクトを共有できますが (この例では電卓はすべてのスレッドによって共有されます)、オブジェクトは属性を共有できません (プリミティブのように、オブジェクトへの参照自体も共有されず、同じ場所を指すだけです)。 )。したがって、1 つのスレッドだけがオブジェクトを変更するようにするために、同期ロック システムが使用されます。

于 2013-07-24T17:15:24.733 に答える
-1

待機および通知メソッドは常にオブジェクトで呼び出されるため、それが Thread オブジェクトであるか単純なオブジェクト (Thread クラスを拡張しない) であるかに関係なく、例を指定すると、すべての疑問が解消されます。

クラス ObjB で wait と notify を呼び出しました。これは Thread クラスなので、wait と notify は任意のオブジェクトで呼び出されると言えます。

public class ThreadA {
    public static void main(String[] args){
        ObjB b = new ObjB();
        Threadc c = new Threadc(b); 
        ThreadD d = new ThreadD(b);
        d.setPriority(5);
        c.setPriority(1);
        d.start();
        c.start();
    }
}

class ObjB {
    int total;
    int count(){
        for(int i=0; i<100 ; i++){
            total += i;
        }
        return total;
    }}


class Threadc extends Thread{
    ObjB b;
    Threadc(ObjB objB){
        b= objB;
    }
    int total;
    @Override
    public void run(){
        System.out.print("Thread C run method");
        synchronized(b){
            total = b.count();
            System.out.print("Thread C notified called ");
            b.notify();
        }
    }
}

class ThreadD extends Thread{
    ObjB b;
    ThreadD(ObjB objB){
        b= objB;
    }
    int total;
    @Override
    public void run(){
        System.out.print("Thread D run method");
        synchronized(b){
            System.out.println("Waiting for b to complete...");
            try {
                b.wait();
                System.out.print("Thread C B value is" + b.total);
                } 
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
}
于 2016-09-25T18:33:50.493 に答える