Java で wait() メソッドと Notice() メソッドを使用して共有リソースのインスタンスを操作する方法

黄舟
リリース: 2017-10-11 09:52:41
オリジナル
1365 人が閲覧しました

この記事では、Java が共有リソースを操作するために wait() Notice() メソッドを使用する方法を主に詳しく紹介します。興味のある方は参照してください。

Java の複数のスレッドはリソースを共有します。 )、notify()、notifyAll() メソッドはローカル メソッドであり最終メソッドであり、オーバーライドできません。

2) オブジェクトの wait() メソッドを呼び出すと、現在のスレッドがブロックされる可能性があり、現在のスレッドはこのオブジェクトのモニター (つまり、ロック、またはモニター) を所有する必要があります

3) オブジェクトの Notice() メソッドを呼び出すこのオブジェクトのモニターを待機しているスレッドをウェイクアップできます。このオブジェクトのモニターを待機しているスレッドが複数ある場合、そのうちの 1 つだけをウェイクアップできます。4) NoticeAll() メソッドを呼び出すと、すべてのスレッドをウェイクアップできます。このオブジェクトを待機しているスレッド。 監視スレッド

Java には、PV 操作、プロセス相互排他などに関連するメソッドはありません。 JAVA のプロセス同期は、synchronized() を通じて実現されます。Java の synchronized() メソッドは、Java のオブジェクト クラス オブジェクトの後にある相互排他的なメモリ ブロックに似ていることに注意してください。スレッドがメモリ ロックを取得すると、他のスレッドはメモリにアクセスできなくなり、Java での単純な同期と相互排他操作が実現されます。この原則を理解すると、synchronized(this) と synchronized(static XXX) の違いが理解できるようになります。 synchronized はメモリ ブロックのメモリ ロックに適用されるため、そのメモリ ロックはクラスのオブジェクトを表します。同じオブジェクト 相互に排他的な操作。静的メンバーはクラスに対して排他的であり、そのメモリ空間はクラスのすべてのメンバーによって共有されます。これにより、synchronized() は静的メンバーをロックします。これはクラスをロックすることと同じです。 、クラスのすべてのメンバー間で相互排他を実装するには、このクラスのインスタンスに同時にアクセスできるスレッドは 1 つだけです。スレッド間で相互にウェイクアップする必要がある場合は、Object クラスの wait() メソッドと nofity() メソッドを使用する必要があります。

こんなに話しても理解できないかもしれないので、マルチスレッドを使用して連続 1,2,1,2,1,2,1,2,1,2 出力を実現する例を使用して問題を説明しましょう。 。

package com.study.thread;
/**
 * 多线程
 * @ClassName: PrintFile 
 * @date 2017年10月10日 下午4:05:04
 */
public class PrintFile implements Runnable{
  //当前线程id
  private int id ;
  //共享资源
  public byte[] res ;
  
  //如果类里写了有参构造器,而任然想保留无参数构造方法,则必须显式的写出该方法。
  public PrintFile() {
    super();
//    System.out.println("我是构造器"); 
  }

  public PrintFile(int id, byte[] res) {
    //构造器中使用super()/this(),必须放在第一行。
    this(); 
    this.id = id;
    this.res = res;
  }

  //静态计数器
  public static int count = 5;
  
  @Override
  public void run() {
    synchronized (res) {
      while(count-->=0){
        try {
          res.notify();//唤醒其他线程中的某一个(唤醒等待res的其他线程,当前线程执行完后要释放锁)
          System.out.println("当前线程id值:"+id);
          
          res.wait();//当前线程阻塞,等待被唤醒
          System.out.println("现在执行的线程是"+Thread.currentThread().getName()+",--wait()后的代码继续执行:"+id);
          
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      return; 
    }
  }
}
ログイン後にコピー

テスト:


package com.study.thread;

public class PrintFileTest {
 public static void main(String[] args) {
  byte[] res = new byte[]{0,1,2};//共享资源
  PrintFile p1 = new PrintFile(1, res);
  PrintFile p2 = new PrintFile(2, res);
  
  Thread t1 = new Thread(p1, "a");
  Thread t2 = new Thread(p2, "b");
    
  t1.start();
  t2.start();
 }
}
ログイン後にコピー

結果:


現在のスレッドID値: 1

現在のスレッドID値: 2

現在実行されているスレッドはaであり、--wait()の後のコードは継続します。実行: 1

現在のスレッド ID 値: 1

現在実行中のスレッドは b、--wait() の後のコードは実行を継続します: 2
現在のスレッド ID 値: 2
現在実行中のスレッドは a、- の後のコード-wait() コードは実行を継続します: 1
現在のスレッド ID 値: 1
現在実行中のスレッドは b, --wait() --wait() の後のコードは実行を継続します: 2
現在のスレッド ID 値: 2
現在実行中のスレッドは a, --wait () 以降のコードは実行を継続します: 1

このような結果が発生する理由を以下に説明します:

まず、スレッド 1 と 2 が開始されると仮定します。最初に run メソッドを実行してリソースを取得します (実際には不確実です)。 オブジェクト a のロックを取得し、while ループに入ります (複数回の出力を制御するために使用されます): この時点で、オブジェクトは wake-1 を呼び出します。これは、同期ブロックが実行された後、ロックを解放し、リソースを待機しているスレッドに渡します。 出力 1;

3。これは、この時点からオブジェクト ロックを所有するスレッド (つまり、ここではスレッド No. 1) が CPU 制御を解放することを意味し、ロックが解放され、スレッドはブロッキング状態になります。同期ブロックは実行されていないため、1 は効果がありません。

4. これより前の時点で、スレッド 2 は run メソッドを実行しましたが、オブジェクト a のロックを取得できなかったため、実行を続けることができません。しかし、3ステップ後にaのロックを取得します。このとき、aのウェイクアップメソッドnotify()を実行します。これは、同期ブロックの実行後にロックを解放することを意味します。 put リソース a を待機しているスレッドにロックが渡されます

5. 出力 2、つまり、この時点からオブジェクト ロックを所有するスレッド (スレッド) を実行します。ここでは No.2) CPU 制御を解放します。 ロックが解放され、スレッドはブロッキング状態になります。同期ブロックが実行されていないため、スレッドの 4 段階のウェイクアップ方法は一時的に実行されません。 2 番は機能しません。

7. この時点で、スレッド 1 が実行されます。 ステップ 3 では、オブジェクト ロックが使用されていないことがわかり、ステップ 3 の wait メソッド以降のコードが実行され続けます。したがって、出力は次のようになります: ------スレッド 1 がロックを取得し、wait() の後のコードは実行を継続します: 1;

8. この時点で、while ループは条件を満たし、実行を継続します。 、スレッド No. 1 のウェイクアップ メソッドを実行します。これは、同期ブロックの実行後にロックを解放します。

10. 待機中のメソッド 1 を実行し、リソース ロック;

11. この時点で、スレッド 2 は再度ロックを取得し、ステップ 6 を実行し、wait メソッドの後にコードを実行し続けるため、出力は次のようになります。 ------ スレッド 2 がロックを取得します。 wait () の後のコードは実行を続けます: 2;

12. while ループを実行し続けて 2; を実行します。 2つの方法がありますが、これもプログラムに問題があり、whileループが条件を満たさない場合、リソースを待っているスレッドが確実に存在するため、メインスレッドは終了しません。もちろん、このプログラムの目的は、これら 2 つの方法の使用方法を示すことだけです。

概要:

wait() メソッドと notify() は synchronized(resource) と一緒に使用する必要があります。つまり、wait と notification は、リソース ロックを取得したスレッド上で動作します。構文の観点からは、Obj.wait() と Obj.notify は synchronized(Obj){...} ステートメント ブロック内にある必要があります。機能的に言​​えば、オブジェクト ロックを取得した後、wait() スレッドは CPU 制御とオブジェクト ロックを積極的に解放し、同時にこのスレッドはスリープします。別のスレッドがオブジェクトのnotify()を呼び出してスレッドをウェイクアップするまで、オブジェクトのロックを取得し続けて実行を続けることができます。対応するnotify()は、オブジェクトのロックの解放操作です。 [したがって、wait メソッドとnotify メソッドの両方がオブジェクトのロックを解放できることがわかりますが、wait メソッドは CPU 制御も解放します。つまり、その背後にあるコードは実行を停止し、スレッドはブロック状態になりますが、notify メソッドは解放しません。 CPU は直ちに制御しますが、対応する synchronized(){} ステートメント ブロックの実行が終了すると、ロックは自動的に解放されます。 】ロックを解放した後、JVM はリソースを待っているスレッドの中からスレッドを選択し、それにオブジェクト ロックを付与し、スレッドをウェイクアップして実行を継続します。これにより、スレッド間の同期とウェイクアップ操作が提供されます。 Thread.sleep() と Object.wait() は両方とも、現在のスレッドを一時停止して CPU 制御を解放できます。主な違いは、Object.wait() は同期ブロック内で CPU を解放しながらオブジェクトのロック制御を解放することです。 sleep() メソッドはロックを解放せず、CPU 制御のみを解放します。

以上がJava で wait() メソッドと Notice() メソッドを使用して共有リソースのインスタンスを操作する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート