ホームページ > Java > &#&チュートリアル > JAVAマルチスレッドにおけるスレッド間の通信方法を深く理解する

JAVAマルチスレッドにおけるスレッド間の通信方法を深く理解する

高洛峰
リリース: 2017-01-05 17:00:29
オリジナル
1905 人が閲覧しました

1. はじめに

このまとめでは、JAVA マルチスレッドにおけるスレッド間の通信方法について、主にコードとテキストを組み合わせて説明するため、書籍からいくつかのサンプルコードを抜粋しました。

2つ目、スレッド間の通信方法

​​①同期

ここで言う同期とは、synchronizedキーワードを介した複数のスレッド間の通信を指します。

参考例:

public class MyObject {
 
  synchronized public void methodA() {
    //do something....
  }
 
  synchronized public void methodB() {
    //do some other thing
  }
}
 
public class ThreadA extends Thread {
 
  private MyObject object;
//省略构造方法
  @Override
  public void run() {
    super.run();
    object.methodA();
  }
}
 
public class ThreadB extends Thread {
 
  private MyObject object;
//省略构造方法
  @Override
  public void run() {
    super.run();
    object.methodB();
  }
}
 
public class Run {
  public static void main(String[] args) {
    MyObject object = new MyObject();
 
    //线程A与线程B 持有的是同一个对象:object
    ThreadA a = new ThreadA(object);
    ThreadB b = new ThreadB(object);
    a.start();
    b.start();
  }
}
ログイン後にコピー

スレッド A とスレッド B は MyObject クラスの同じオブジェクトを保持しているため、2 つのスレッドは異なるメソッドを呼び出す必要がありますが、同期して実行されます。例: スレッド B はスレッド A を待つ必要があります。 MethodA() メソッドを実行すると、methodB() メソッドを実行できます。このようにして、スレッド A とスレッド B は通信を実現します。

この方法は基本的に「共有メモリ」通信です。複数のスレッドが同じ共有変数にアクセスする必要があります。ロックを取得した (アクセス許可を取得した) 人は誰でもそれを実行できます。

②while ポーリングメソッド

コードは次のとおりです:

import java.util.ArrayList;
import java.util.List;
 
public class MyList {
 
  private List<String> list = new ArrayList<String>();
  public void add() {
    list.add("elements");
  }
  public int size() {
    return list.size();
  }
}
 
import mylist.MyList;
 
public class ThreadA extends Thread {
 
  private MyList list;
 
  public ThreadA(MyList list) {
    super();
    this.list = list;
  }
 
  @Override
  public void run() {
    try {
      for (int i = 0; i < 10; i++) {
        list.add();
        System.out.println("添加了" + (i + 1) + "个元素");
        Thread.sleep(1000);
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
 
import mylist.MyList;
 
public class ThreadB extends Thread {
 
  private MyList list;
 
  public ThreadB(MyList list) {
    super();
    this.list = list;
  }
 
  @Override
  public void run() {
    try {
      while (true) {
        if (list.size() == 5) {
          System.out.println("==5, 线程b准备退出了");
          throw new InterruptedException();
        }
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
 
import mylist.MyList;
import extthread.ThreadA;
import extthread.ThreadB;
 
public class Test {
 
  public static void main(String[] args) {
    MyList service = new MyList();
 
    ThreadA a = new ThreadA(service);
    a.setName("A");
    a.start();
 
    ThreadB b = new ThreadB(service);
    b.setName("B");
    b.start();
  }
}
ログイン後にコピー

このメソッドでは、スレッド A が常に条件を変更し、スレッド ThreadB が while を通じてこの条件 (list.size()==5) が検出されるかどうかを常にチェックします。ステートメントが確立され、スレッド間の通信が実現されます。ただし、この方法では CPU リソースが無駄になります。これがリソースの無駄であると言われる理由は、JVM スケジューラが実行のために CPU をスレッド B に渡すとき、「有用な」作業は行わず、特定の条件が真であるかどうかを常にテストしているだけだからです。これは、現実の生活において、人が他のことをするのではなく、電話の画面を見つめ続けるのと似ています。電話がかかってくると、電話が鳴って電話がかかってきたことを知らせます。

③待機/通知メカニズム

コードは次のとおりです:

import java.util.ArrayList;
import java.util.List;
 
public class MyList {
 
  private static List<String> list = new ArrayList<String>();
 
  public static void add() {
    list.add("anyString");
  }
 
  public static int size() {
    return list.size();
  }
}
 
 
public class ThreadA extends Thread {
 
  private Object lock;
 
  public ThreadA(Object lock) {
    super();
    this.lock = lock;
  }
 
  @Override
  public void run() {
    try {
      synchronized (lock) {
        if (MyList.size() != 5) {
          System.out.println("wait begin "
              + System.currentTimeMillis());
          lock.wait();
          System.out.println("wait end "
              + System.currentTimeMillis());
        }
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
 
 
public class ThreadB extends Thread {
  private Object lock;
 
  public ThreadB(Object lock) {
    super();
    this.lock = lock;
  }
 
  @Override
  public void run() {
    try {
      synchronized (lock) {
        for (int i = 0; i < 10; i++) {
          MyList.add();
          if (MyList.size() == 5) {
            lock.notify();
            System.out.println("已经发出了通知");
          }
          System.out.println("添加了" + (i + 1) + "个元素!");
          Thread.sleep(1000);
        }
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
 
public class Run {
 
  public static void main(String[] args) {
 
    try {
      Object lock = new Object();
 
      ThreadA a = new ThreadA(lock);
      a.start();
 
      Thread.sleep(50);
 
      ThreadB b = new ThreadB(lock);
      b.start();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
ログイン後にコピー

スレッド A は、操作を実行する前に、特定の条件が満たされる (list.size()==5) まで待機する必要があります。スレッド B はリストに要素を追加し、リストのサイズを変更します。

AとBはどのようにコミュニケーションをとりますか?言い換えれば、スレッド A は、list.size() がすでに 5 であることをどのようにして知るのでしょうか?

ここではObjectクラスのwait()メソッドとnotify()メソッドが使用されています。

条件が満たされない場合(list.size() !=5)、スレッドAはwait()を呼び出してCPUを放棄し、ブロッキング状態に入ります。 ---②ポーリング中のようにCPUを占有することはありません

条件が満たされると、スレッドBはnotify()を呼び出してスレッドAに通知します。いわゆる通知スレッドAは、スレッドAをウェイクアップしてランナブルに入れます。州。

この方法の利点の 1 つは、CPU 使用率が向上することです。

しかし、いくつかの欠点もあります。たとえば、スレッド B が最初に実行され、一度に 5 つの要素を追加して、notify() を呼び出して通知を送信しますが、スレッド A が実行されて wait( が呼び出されるとき、この時点ではスレッド A はまだ実行中です。 )、そうすると決して目覚めることはありません。スレッド B はすでに通知を送信しており、今後は通知を送信しないためです。これは、通知が早すぎるとプログラムの実行ロジックが中断されることを示しています。

JAVAマルチスレッドにおけるスレッド間の通信方法を深く理解するための上記の記事は、編集者が共有したすべての内容であり、皆様の参考になれば幸いです。また、皆様にもPHP中国語をサポートしていただければ幸いです。 Webサイト。

JAVA マルチスレッドにおけるスレッド間の通信方法をより深く理解するには、PHP 中国語 Web サイトに注目してください。


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