Java - スレッド間通信

ようこそ、Javaプログラマー志願者の皆さん!今日、私たちはJavaのスレッド間通信の魔法の世界に興味深い旅を踏み出します。皆さんの親しみのある近所のコンピュータサイエンスの先生として、私はこの魅力的なトピックをガイドします。だから、お気に入りの飲み物をお持ち、快適に座り、一緒に飛び込みましょう!

Java - Inter-thread Communication

スレッド間通信とは何ですか?

リレー競争を想像してみてください。あなたはちょうど適切な瞬間にチームメイトにバトンを渡さなければなりません。それは、プログラミング世界におけるスレッド間通信の基本とも言えます。それは、Javaプログラム内の異なるスレッドがお互いにどのように話し合い、行動を調整し、情報を共有するかを意味します。

スレッド間通信の重要性は何ですか?

スレッド間通信は、効率的で同期されたプログラムを作成するために非常に重要です。これがなければ、私たちのスレッドは別の競争に参加している走者のように、効果的に協力したりリソースを共有することができません。

スレッド間通信に使用されるメソッド

Javaはスレッド間通信のためのいくつかのメソッドを提供しています。それらを便利な表にまとめてみましょう:

メソッド 説明
wait() 現在のスレッドを、他のスレッドがこのオブジェクトに対してnotify()またはnotifyAll()を呼び出すまで待機させます
notify() このオブジェクトのモニターを待っている1つのスレッドを起床させます
notifyAll() このオブジェクトのモニターを待っているすべてのスレッドを起床させます

では、これらを分解してどのように動作するかを見ていきましょう!

wait() メソッド

wait() メソッドは、スレッドに「ねえ、誰かがあなたにふれてくるまで休憩しよう」と言うようなものです。以下はその動作方法です:

synchronized(object) {
while(condition) {
object.wait();
}
}

このコードでは、以下のことを行います:

  1. オブジェクトを同期してスレッドセーフを確保します。
  2. whileループで条件を確認します。
  3. 条件が真であれば、wait() を呼び出し、スレッドを一時停止して通知を待ちます。

notify() メソッド

notify() メソッドは、待機しているスレッドに「おはよう!今はあなたの番だ」と言うようなものです。以下はその使用方法です:

synchronized(object) {
// 条件を変更
condition = true;
object.notify();
}

このコードでは、以下のことを行います:

  1. wait() 呼び出しと同じオブジェクトに対して同期します。
  2. 待機しているスレッドが確認している条件を変更します。
  3. notify() を呼び出して、1つの待機スレッドを起床させます。

notifyAll() メソッド

notifyAll() メソッドは、「みんなおはよう!」と叫ぶようなものです。これは、すべての待機スレッドにアラートを出したいときに使用されます。以下はその例です:

synchronized(object) {
// 条件を変更
condition = true;
object.notifyAll();
}

これは notify() とよく似ていますが、1つの待機スレッドの代わりにすべての待機スレッドを起床させます。

実世界の例:プロデューサー-コンシューマープロブレム

これらすべてを古典的な例で組み合わせて見ましょう:プロデューサー-コンシューマープロブレムです。パン屋で1人(プロデューサー)がパンを作り、もう1人(コンシューマー)がそれを売ると想像してみてください。彼らは限られた棚スペースを共有しています。

以下はこれをJavaでどのように実装できるかの例です:

class Bakery {
private int breads = 0;
private final int CAPACITY = 5;

public synchronized void produceBread() throws InterruptedException {
while (breads == CAPACITY) {
System.out.println("Shelf is full! Baker is waiting...");
wait();
}
breads++;
System.out.println("Baker made a bread. Total: " + breads);
notify();
}

public synchronized void sellBread() throws InterruptedException {
while (breads == 0) {
System.out.println("No bread! Seller is waiting...");
wait();
}
breads--;
System.out.println("Sold a bread. Remaining: " + breads);
notify();
}
}

class Baker implements Runnable {
private Bakery bakery;

public Baker(Bakery bakery) {
this.bakery = bakery;
}

public void run() {
for (int i = 0; i < 10; i++) {
try {
bakery.produceBread();
Thread.sleep(1000); // Time to bake
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

class Seller implements Runnable {
private Bakery bakery;

public Seller(Bakery bakery) {
this.bakery = bakery;
}

public void run() {
for (int i = 0; i < 10; i++) {
try {
bakery.sellBread();
Thread.sleep(1500); // Time between sales
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

public class BakeryDemo {
public static void main(String[] args) {
Bakery bakery = new Bakery();
Thread baker = new Thread(new Baker(bakery));
Thread seller = new Thread(new Seller(bakery));

baker.start();
seller.start();
}
}

以下にこれを分解して見ます:

  1. Bakery クラスはパンの在庫を管理します。
  2. produceBread() メソッドはパンを作るパン屋を表しており、棚が満ちた場合、パン屋は待機します。
  3. sellBread() メソッドはパンを売る売り手を表しており、パンがない場合、売り手は待機します。
  4. プロデュースや販売の条件が適切でない場合に wait() を使用します。
  5. プロデュースや販売した後に notify() を使用して他のスレッドにアラートを出します。
  6. BakerSeller クラスは別のスレッドで実行され、パンを作ったり売ったりし続けます。

このプログラムを実行すると、パン屋と売り手が一緒に働いて、必要に応じて待機し、進めることができるように通知するのを見ることができます。まるでよく調整されたダンスを見ているようです!

結論

それでは、皆さん!私たちはJavaのスレッド間通信の旅を終えました。私たちは wait()notify()、および notifyAll() を使ってスレッドがどのようにして行動を調整するかを見ました。まさに仮想のパン屋を作り、これらの概念がどのように動作するかを見ました!

パン屋の例で見たように、良いスレッド間通信はバランスと調整にあります。それは、どのようにして働き、待機し、他の人にシグナルを送るかを知ることです。これをマスターすることで、効率的でよく調整されたJavaプログラムを作成する道を開くでしょう。

練習を続け、興味深いことを探し続け、幸せなコーディングを!そして、プログラミングも人生も、良いコミュニケーションが成功の鍵であることを忘れずに。次回まで、皆さんの親しみのある近所のコンピュータサイエンスの先生として、さようなら!

Credits: Image by storyset