Heim  >  Artikel  >  Java  >  So verwenden Sie die Methoden wait() und notify() in Java, um Instanzen gemeinsam genutzter Ressourcen zu betreiben

So verwenden Sie die Methoden wait() und notify() in Java, um Instanzen gemeinsam genutzter Ressourcen zu betreiben

黄舟
黄舟Original
2017-10-11 09:52:411371Durchsuche

In diesem Artikel wird hauptsächlich detailliert beschrieben, wie Java die Methode wait() notify() zum Betreiben gemeinsamer Ressourcen verwendet. Interessierte Freunde können sich auf

Gemeinsame Java-Ressourcen beziehen >

1) Die Methoden wait(), notify() und notifyAll() sind lokale Methoden und letzte Methoden und können nicht überschrieben werden.

 2) Das Aufrufen der wait()-Methode eines Objekts kann den aktuellen Thread blockieren, und der aktuelle Thread muss den Monitor (d. h. die Sperre oder den Monitor) dieses Objekts besitzen

 3) Aufruf Die notify()-Methode eines Objekts kann einen Thread aufwecken, der auf den Monitor dieses Objekts wartet. Wenn mehrere Threads auf den Monitor dieses Objekts warten, kann nur einer der Threads aufgeweckt werden 🎜> 4) Rufen Sie die notifyAll()-Methode auf, um alle Threads aufzuwecken, die auf die Überwachung dieses Objekts warten.

In Java gibt es keine Methoden, die PV-Operationen ähneln, den gegenseitigen Ausschluss verarbeiten usw. Die Prozesssynchronisation von JAVA wird durch synchronisiert () erreicht. Es ist zu beachten, dass die synchronisierte () -Methode von Java dem sich gegenseitig ausschließenden Speicherblock im Betriebssystemkonzept ähnelt Ein Thread erwirbt die Speichersperre, andere Threads können nicht auf den Speicher zugreifen, wodurch einfache Synchronisations- und gegenseitige Ausschlussoperationen in Java realisiert werden. Wenn Sie dieses Prinzip verstehen, können Sie den Unterschied zwischen „synced(this)“ und „synchized(static XXX)“ für eine Speichersperre für einen Speicherblock verstehen. Das Schlüsselwort „this“ stellt ein Objekt der Klasse dar, also ist seine Speichersperre für das gleiche Objekt Sich gegenseitig ausschließende Operation, und statische Mitglieder sind exklusiv für die Klasse, und ihr Speicherplatz wird von allen Mitgliedern der Klasse gemeinsam genutzt. Dies führt dazu, dass synchronisiert() die statischen Mitglieder sperrt, was dem Sperren der Klasse entspricht , zwischen allen Mitgliedern der Klasse, um den gegenseitigen Ausschluss zu implementieren, kann nur ein Thread gleichzeitig auf Instanzen dieser Klasse zugreifen. Wenn Sie sich zwischen Threads gegenseitig aufwecken müssen, müssen Sie die Methoden wait() und nofity() der Object-Klasse verwenden.

Nachdem Sie so viel gesprochen haben, verstehen Sie es möglicherweise nicht. Lassen Sie uns das Problem anhand eines Beispiels veranschaulichen. Verwenden Sie Multithreading, um kontinuierliche 1,2,1,2,1,2,1,2 zu erreichen. 1,2 Ausgang.


Test:

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; 
    }
  }
}


Ergebnis:

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();
 }
}
Aktueller Thread-ID-Wert :1

Aktueller Thread-ID-Wert: 2

Der aktuell ausgeführte Thread ist a, der Code nach --wait() wird weiterhin ausgeführt: 1

Aktueller Thread-ID-Wert: 1
Der aktuell ausgeführte Thread ist b, der Code nach --wait() wird weiterhin ausgeführt: 2
Aktueller Thread-ID-Wert: 2
Der aktuell ausgeführte Thread ist a, der Code nach --wait() wird weiterhin ausgeführt: 1
aktueller Thread-ID-Wert: 1
Der aktuell ausgeführte Thread ist b, --wait() Der Code nach --wait() wird weiterhin ausgeführt: 2
Aktueller Thread-ID-Wert: 2
Der Thread Derzeit wird ein,--wait() ausgeführt. Der folgende Code wird weiterhin ausgeführt: 1

Im Folgenden wird erklärt, warum ein solches Ergebnis auftritt:

Zuerst werden die Threads 1 und 2 gestartet Angenommen, Thread 1 führt zuerst die Ausführungsmethode aus, um Ressourcen abzurufen (tatsächlich ist dies ungewiss), erhält die Sperre von Objekt a und tritt in die while-Schleife ein (wird zur Steuerung mehrerer Ausgaberunden verwendet):

1 Zu diesem Zeitpunkt ruft das Objekt seine Weckmethode notify() auf, was bedeutet, dass dieser Synchronisationsblock ausgeführt wird. Nach Abschluss gibt es die Sperre frei und übergibt sie an den Thread, der auf Ressource a wartet

2. Ausgabe 1;

3. Das Objekt führt die Wartemethode aus, was bedeutet, dass es von diesem Moment an der Thread der Objektsperre (hier Thread Nr. 1) ist, der die CPU-Steuerung freigibt. hebt die Sperre auf und der Thread wechselt in den blockierten Zustand. Der nachfolgende Code wird vorübergehend nicht ausgeführt, sodass 1 keine Auswirkung hat.

Irgendwann zuvor wurde Thread 2 ausgeführt Die Ausführungsmethode konnte jedoch nicht weiter ausgeführt werden, da sie die Sperre von Objekt a nicht erhalten hat. Nach drei Schritten wurde jedoch die Aktivierung von a durchgeführt. ) bedeutet auf die gleiche Weise, dass nach der Ausführung des Synchronisationsblocks die Sperre an den Thread übergeben wird, der auf eine Ressource wartet

5 6. Das Ausführen der Wartemethode von a bedeutet, dass der Thread, der ab diesem Zeitpunkt die Objektsperre besitzt (hier Thread Nr. 2), die CPU-Steuerung freigibt, die Sperre aufhebt und der Thread in den Blockierungszustand wechselt nicht vorübergehend ausgeführt werden, da der Synchronisierungsblock noch nicht ausgeführt wurde. Die 4-stufige Aktivierungsmethode von Thread Nr. 2 funktioniert zu diesem Zeitpunkt nicht. 1 führt Schritt 3 aus und stellt fest, dass die Objektsperre nicht verwendet wird, und führt daher weiterhin Schritt 3 aus. Im Code nach der Wartemethode lautet die Ausgabe: ------Thread 1 erhält die Sperre und der Code danach wait() läuft weiter: 1;

8 Zu diesem Zeitpunkt erfüllt die while-Schleife die Bedingungen und wird weiterhin ausgeführt. Führen Sie daher die Weckmethode von Thread Nr. 1 erneut aus es wird die Sperre aufheben, nachdem der Synchronisationsblock ausgeführt wurde;

10. Führen Sie die Wartemethode aus und geben Sie die Ressourcensperre auf >

11. Zu diesem Zeitpunkt hat Thread 2 die Sperre erneut erhalten und führt den Code nach der Wartemethode weiter aus. Die Ausgabe lautet also: ------Thread 2 erhält die Sperre. Warten Sie, bis der Code nach () weiterläuft:

12 Führen Sie die While-Schleife weiter aus und geben Sie 2 aus Ich glaube, dass jeder die Verwendung dieser beiden Methoden bereits verstanden hat, aber es gibt immer noch ein Problem in diesem Programm. Wenn die While-Schleife die Bedingungen nicht erfüllt, werden definitiv noch Threads auf Ressourcen warten, also der Hauptthread wird niemals enden. Der Zweck dieses Programms besteht natürlich nur darin, die Verwendung dieser beiden Methoden zu demonstrieren.

Zusammenfassung:

Die Methode wait() und notify() müssen zusammen mit synchronisiert(resource) verwendet werden. Das heißt, warten und benachrichtigen, um den Thread zu bearbeiten, der die Ressourcensperre erhalten hat. Aus syntaktischer Sicht müssen sich Obj.wait() und Obj.notify innerhalb des synchronisierten (Obj){...}-Anweisungsblocks befinden. Funktionell gesehen gibt der wait()-Thread nach dem Erwerb der Objektsperre aktiv die CPU-Steuerung und die Objektsperre frei und schläft gleichzeitig. Bis ein anderer Thread notify() des Objekts aufruft, um den Thread aufzuwecken, kann er weiterhin die Objektsperre erwerben und die Ausführung fortsetzen. Die entsprechende notify() ist die Freigabeoperation der Objektsperre. [Daher können wir feststellen, dass sowohl die Warte- als auch die Notify-Methode die Sperre des Objekts aufheben können, aber Wait gibt auch die CPU-Steuerung frei, d CPU-Steuerung sofort, aber die Sperre wird automatisch aufgehoben, nachdem die Ausführung des entsprechenden Anweisungsblocks „synchonized(){}“ endet. 】Nach dem Aufheben der Sperre wählt die JVM einen Thread unter den Threads aus, die auf Ressourcen warten, erteilt ihm die Objektsperre, weckt den Thread auf und setzt die Ausführung fort. Dies ermöglicht Synchronisations- und Weckvorgänge zwischen Threads. Sowohl Thread.sleep() als auch Object.wait() können den aktuellen Thread anhalten und die CPU-Steuerung freigeben. Der Hauptunterschied besteht darin, dass Object.wait() die Objektsperrsteuerung freigibt, während die CPU im Synchronisationsblock ist. Die Methode sleep() gibt die Sperre nicht frei, sondern nur die CPU-Steuerung.

Das obige ist der detaillierte Inhalt vonSo verwenden Sie die Methoden wait() und notify() in Java, um Instanzen gemeinsam genutzter Ressourcen zu betreiben. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn