ホームページ  >  記事  >  Java  >  Javaスレッド通信の詳しい説明

Javaスレッド通信の詳しい説明

高洛峰
高洛峰オリジナル
2017-01-05 15:20:481571ブラウズ

スレッド通信は、スレッドの協調動作を保証するために使用されます。一般に、スレッド同期を行う際には、スレッド通信の問題を考慮する必要があります。

1. 従来のスレッド通信

は、通常、Objeclt クラスによって提供される 3 つのメソッドを使用します:

wait() は、他のスレッドが同期の notify() を呼び出すまで、現在のスレッドを待機させ、同期モニターのロックを解放します。 )またはnotifyAll()メソッドを使用してスレッドを起動します。

notify()、この同期モニターで待機しているスレッドを起動します。複数ある場合は、ランダムに 1 つが選択されて起動します。

notifyAll()、これらのスレッドが競合した後、この同期モニターで待機しているすべてのスレッドを起動します。スケジューリングを通じてリソースの場合、スレッドはこの同期モニターのロックを取得し、実行が許可されます。

これら 3 つのメソッドは同期モニター オブジェクトによって呼び出される必要があり、次の 2 つの状況に分けられます。

メソッドを同期する場合、同期モニターはこのオブジェクトであるため、これら 3 つのメソッドを直接呼び出すことができます。

例は次のとおりです:

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

コード ブロックを同期するとき、モニター オブジェクトを使用してこれら 3 つのメソッドを呼び出す必要があります。

例は次のとおりです:

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. Condition を使用してスレッド通信を制御します

Lock オブジェクトを使用して同期を確保する場合は、Condition オブジェクトを使用して調整を確保します。

例は次のとおりです:

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

Condition オブジェクトの await()、singal()、singalAll() は、それぞれ wait()、notify()、notifyAll() メソッドに対応します。

3. ブロッキングキュー BlockingQueue を使用してスレッド通信を制御します

BlockingQueue は Queue インターフェースのサブインターフェースであり、主にスレッド通信に使用されます。キューがいっぱいの場合、コンシューマ スレッドが BlockingQueue から要素を取り出そうとすると、スレッドはブロックされます。キューが空の場合、スレッドはブロックされます。これら 2 つの機能はそれぞれ、ブロッキングをサポートする 2 つのメソッド put(E e) と take() に対応します

例は次のとおりです:

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 には 5 つの実装クラスがあります:

ArrayBlockingQueue BlockingQueue ベースの array

LinkedBlockingQueueリンク リスト

PriorityBlockingQueue によって実装される BlockingQueue キュー内の要素は Comparable インターフェイスを実装する必要があり、要素の並べ替えは Comparator に従ってカスタマイズされます。

SynchronousQueue 同期キューでは、キューへのアクセス操作を交互に実行する必要があります。

DelayQueue コレクション要素は Delay インターフェースを実装する必要があります。キュー内の要素は、Delay インターフェースのメソッド getDelay() の戻り値に従ってソートされます。

以上がこの記事の全内容です。皆さんの学習に役立つことを願っています。また、皆さんも PHP 中国語 Web サイトをサポートしていただければ幸いです。

Java スレッド通信に関連するその他の記事については、PHP 中国語 Web サイトに注目してください。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。