Heim  >  Artikel  >  Java  >  Detaillierte Erläuterung der Java-Thread-Kommunikation

Detaillierte Erläuterung der Java-Thread-Kommunikation

高洛峰
高洛峰Original
2017-01-05 15:20:481571Durchsuche

Thread-Kommunikation wird verwendet, um den koordinierten Betrieb von Threads sicherzustellen. Im Allgemeinen müssen Thread-Kommunikationsprobleme bei der Thread-Synchronisierung berücksichtigt werden.

1. Die traditionelle Thread-Kommunikation

verwendet normalerweise die drei von der Objeclt-Klasse bereitgestellten Methoden:

wait() bewirkt, dass der aktuelle Thread wartet und die Sperre der Synchronisierung aufhebt überwachen, bis andere Threads die Methode notify() oder notifyAll() des Synchronisationsmonitors aufrufen, um den Thread aufzuwecken.

notify(), weckt die Threads auf, die auf diesem Synchronisationsmonitor warten. Wenn es mehrere gibt, wird einer zufällig zum Aufwecken ausgewählt

notifyAll(), weckt alle darauf wartenden Threads auf Synchronisationsmonitor: Nachdem diese Threads durch Planung um Ressourcen konkurrieren, erhält ein Thread die Sperre dieses Synchronisationsmonitors und wird dann ausgeführt.

Diese drei Methoden müssen vom Synchronisationsmonitorobjekt aufgerufen werden und sind in zwei Situationen unterteilt:

Beim Synchronisieren der Methode können diese drei Methoden direkt aufgerufen werden, da der Synchronisationsmonitor dieses Objekt ist .

Ein Beispiel ist wie folgt:

public class SyncMethodThreadCommunication {
  static class DataWrap{
    int data = 0;
    boolean flag = false;
     
    public synchronized void addThreadA(){
      if (flag) {
        try {
          wait();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      } 
       
      data++;
      System.out.println(Thread.currentThread().getName() + " " + data);
      flag = true;
      notify();
    }
     
    public synchronized void addThreadB() {
      if (!flag) {
        try {
          wait();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      } 
       
      data++;
      System.out.println(Thread.currentThread().getName() + " " + data);
      flag = false;
      notify();
    }
  }
   
  static class ThreadA extends Thread {
    private DataWrap data;
     
    public ThreadA(DataWrap dataWrap) {
      this.data = dataWrap;
    }
     
    @Override
    public void run() {
      for (int i = 0; i < 10; i++) {
        data.addThreadA();
      }
    }
  }
   
  static class ThreadB extends Thread {
    private DataWrap data;
     
    public ThreadB(DataWrap dataWrap) {
      this.data = dataWrap;
    }
     
    @Override
    public void run() {
      for (int i = 0; i < 10; i++) {
        data.addThreadB();
      }
    }
  }
   
  public static void main(String[] args) {
    //实现两个线程轮流对数据进行加一操作
    DataWrap dataWrap = new DataWrap();
     
    new ThreadA(dataWrap).start();
    new ThreadB(dataWrap).start();
  }
 
}

Beim Synchronisieren eines Codeblocks müssen Sie das Monitorobjekt verwenden, um diese drei Methoden aufzurufen.

Beispiele sind wie folgt:

public class SyncBlockThreadComminication {
  static class DataWrap{
    boolean flag;
    int data;
  }
   
  static class ThreadA extends Thread{
    DataWrap dataWrap;
     
    public ThreadA(DataWrap dataWrap){
      this.dataWrap = dataWrap;
    }
     
    @Override
    public void run() {
      for(int i = 0 ; i < 10; i++) {
        synchronized (dataWrap) {
          if (dataWrap.flag) {
            try {
              dataWrap.wait();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
           
          dataWrap.data++;
          System.out.println(getName() + " " + dataWrap.data);
          dataWrap.flag = true;
          dataWrap.notify();
        }  
      }
    }
  }
   
  static class ThreadB extends Thread{
    DataWrap dataWrap;
     
    public ThreadB(DataWrap dataWrap){
      this.dataWrap = dataWrap;
    }
     
    @Override
    public void run() {
      for (int i = 0; i < 10; i++) {
          synchronized (dataWrap) {
            if (!dataWrap.flag) {
              try {
                dataWrap.wait();
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
             
            dataWrap.data++;
            System.out.println(getName() + " " + dataWrap.data);
            dataWrap.flag = false;
            dataWrap.notify();
          }
        }  
      }
       
  }
  public static void main(String[] args) {
    //实现两个线程轮流对数据进行加一操作
     
    DataWrap dataWrap = new DataWrap();
    new ThreadA(dataWrap).start();
    new ThreadB(dataWrap).start();
  }
 
}

2. Verwenden Sie Condition, um die Thread-Kommunikation zu steuern.

Wenn Sie das Lock-Objekt verwenden, um die Synchronisierung sicherzustellen, verwenden Sie das Condition-Objekt, um die Koordination sicherzustellen.

Ein Beispiel ist wie folgt:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
import com.sun.media.sound.RIFFInvalidDataException;
 
import javafx.scene.chart.PieChart.Data;
 
public class SyncLockThreadCommunication {
  static class DataWrap {
    int data;
    boolean flag;
     
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
     
    public void addThreadA() {
      lock.lock();
      try {
        if (flag) {
          try {
            condition.await();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
         
        data++;
        System.out.println(Thread.currentThread().getName() + " " + data);
        flag = true;
        condition.signal();
      } finally {
        lock.unlock();
      }
    }
     
    public void addThreadB() {
      lock.lock();
      try {
        if (!flag) {
          try {
            condition.await();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
         
        data++;
        System.out.println(Thread.currentThread().getName() + " " + data);
        flag = false;
        condition.signal();
      } finally {
        lock.unlock();
      }
    }
  }
   
  static class ThreadA extends Thread{
    DataWrap dataWrap;
     
    public ThreadA(DataWrap dataWrap) {
      this.dataWrap = dataWrap;
    }
     
    @Override
    public void run() {
      for (int i = 0; i < 10; i++) {
        dataWrap.addThreadA();
      }
    }
  }
   
  static class ThreadB extends Thread{
    DataWrap dataWrap;
     
    public ThreadB(DataWrap dataWrap) {
      this.dataWrap = dataWrap;
    }
     
    @Override
    public void run() {
      for (int i = 0; i < 10; i++) {
        dataWrap.addThreadB();
      }
    }
  }
   
  public static void main(String[] args) {
    //实现两个线程轮流对数据进行加一操作
     
    DataWrap dataWrap = new DataWrap();
    new ThreadA(dataWrap).start();
    new ThreadB(dataWrap).start();
  }
 
}

Await(), singal() und singalAll() des Condition-Objekts entsprechen wait(), notify() und notifyAll()-Methoden.

3. BlockingQueue zur Steuerung der Thread-Kommunikation verwenden

BlockingQueue ist eine Unterschnittstelle der Queue-Schnittstelle. Sie wird hauptsächlich für die Thread-Kommunikation verwendet versucht, in die BlockingQueue einzutreten. Wenn ein Element eingefügt wird und die Warteschlange voll ist, wird der Thread blockiert. Wenn der Verbraucherthread versucht, ein Element aus der BlockingQueue zu entfernen, wird der Thread blockiert, wenn die Warteschlange leer ist. Diese beiden Funktionen entsprechen jeweils zwei Methoden, die das Blockieren unterstützen, put(E e) und take()

Die Beispiele lauten wie folgt:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
 
public class BlockingQueueThreadComminication {
  static class DataWrap{
    int data;
  }
   
  static class ThreadA extends Thread{
    private BlockingQueue<DataWrap> blockingQueue;
     
    public ThreadA(BlockingQueue<DataWrap> blockingQueue, String name) {
      super(name);
      this.blockingQueue = blockingQueue;
    }
     
    @Override
    public void run() {
      for (int i = 0; i < 100; i++) {
        try {
          DataWrap dataWrap = blockingQueue.take();
           
          dataWrap.data++;
          System.out.println(getName() + " " + dataWrap.data);
          sleep(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }
   
  static class ThreadB extends Thread{
    private BlockingQueue<DataWrap> blockingQueue;
    private DataWrap dataWrap;
     
    public ThreadB(BlockingQueue<DataWrap> blockingQueue, DataWrap dataWrap, String name) {
      super(name);
      this.blockingQueue = blockingQueue;
      this.dataWrap = dataWrap;
    }
     
    @Override
    public void run() {
      for (int i = 0; i < 100; i++) {
        try {
          dataWrap.data++;
          System.out.println(getName() + " " + dataWrap.data);
          blockingQueue.put(dataWrap);
          sleep(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }
   
  public static void main(String[] args) {
    ///实现两个线程轮流对数据进行加一操作
     
    DataWrap dataWrap = new DataWrap();
    BlockingQueue<DataWrap> blockingQueue = new ArrayBlockingQueue<>(1);
     
    new ThreadA(blockingQueue, "Consumer").start();
    new ThreadB(blockingQueue, dataWrap, "Producer").start();
  }
 
}

BlockingQueue hat fünf Implementierungsklassen:

ArrayBlockingQueue BlockingQueue-Warteschlange basierend auf Array implementiert

LinkedBlockingQueue BlockingQueue-Warteschlange basierend auf verknüpfter Liste implementiert

Die Elemente in PriorityBlockingQueue müssen die Comparable-Schnittstelle implementieren und die Sortierung der Elemente wird angepasst laut Komparator.

SynchronousQueue ist eine synchrone Warteschlange, bei der Zugriffsvorgänge auf die Warteschlange abwechselnd ausgeführt werden müssen.

DelayQueue-Sammlungselemente müssen die Delay-Schnittstelle implementieren. Die Elemente in der Warteschlange werden nach dem Rückgabewert der Delay-Schnittstellenmethode getDelay() sortiert.

Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er zum Lernen aller beiträgt. Ich hoffe auch, dass jeder die PHP-Chinesisch-Website unterstützt.

Ausführlichere Artikel zur Java-Thread-Kommunikation finden Sie auf der chinesischen PHP-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