HOWTO · Java

Java のミューテックス

Java でミューテックスについてすべてを学ぶ

コンピュータサイエンスの世界では、相互排除またはミューテックスは同時実行制御のプロパティとして知られています。すべてのコンピュータは、スレッドと呼ばれるプログラムされた命令の最小シーケンスを実行します。かつて、コンピューターは単一のスレッドで動作していました。理解を深めるために、さらにいくつかの側面を詳しく見ていきましょう。

スレッド化とマルチスレッド化

CPU はマルチタスク用のスレッドで動作します。各プロセスは、スレッドからスレッドへと非常に高速で絶えずシフトすることによって機能します。たとえば、ビデオを見るとき、ビデオのオーディオは別のスレッドにあり、画像は別のスレッドにあります。これら 2つの間の絶え間ない切り替えは非常に高速であり、マルチスレッドとして知られています。

Java のスレッド

Java でスレッドを作成するには、クラスを拡張し、インターフェースを実装します。マルチスレッドは、CPU 効率を最大化するために、プログラムの 2つ以上の部分を同時に実行できるようにする Java 機能です。スレッドはそのようなプログラムのコンポーネントです。したがって、スレッドはプロセス内の軽量プロセスです。

ミューテックス

マルチスレッドプログラムで 2つ以上のスレッドが共有リソースに同時にアクセスする必要がある場合、予期しない動作が発生する可能性があります。データ構造、入出力デバイス、ファイル、およびネットワーク接続は、共有リソースの例です。

これは競合状態と呼ばれます。プログラムの重要なセクションは、共有リソースにアクセスするプログラムの一部です。その結果、競合状態を回避するために、重要な部分へのアクセスを同期する必要があります。

最も基本的な種類のシンクロナイザーはミューテックス(または相互排除)であり、一度に 1つのスレッドのみがコンピュータープログラムの重要な領域を実行できることを保証します。これは、semaphore と呼ばれるクラスによって実装されます。

スレッドはミューテックスを取得してからクリティカルセクションにアクセスし、最後にミューテックスを解放してクリティカル領域にアクセスします。その間、ミューテックスが解放されるまで、他のすべてのスレッドはブロックされます。スレッドは、クリティカル領域を出るとすぐにクリティカルセクションに入ることができます。

ミューテックスの場合、ロックとロック解除には 2つの方法があります。それらはそれぞれ acquire() および release() として知られています。次に、以下の例を見てください。

Mutex の詳細についてはこちらを参照します。

import java.util.LinkedList; // linked list import
import java.util.concurrent.Semaphore; // semaphore import
public class Mutex {
  static LinkedList<String> WorkingQueue = new LinkedList<String>();
  // track the record of works
  static Semaphore mutex1 = new Semaphore(0); // creating a Semaphore To ImplementLogic
  static Semaphore mutex = new Semaphore(1); // Creating A Mutex
}

上記の例では、mutexmutex1 という名前の 2つの Mutex オブジェクトを作成しました。mutex1 を使用して、2つのスレッド間の切り替えを制御します。リンクリストを作成する理由は、スレッドの実績があるためです。それでは、上記のコードに 2つのスレッドを追加しましょう。ProducerConsumer という名前の 2つのスレッド。

import java.util.LinkedList; // linked list import
import java.util.concurrent.Semaphore; // semaphore import
public class Mutex {
  static LinkedList<String> WorkingQueue = new LinkedList<String>();
  // track the record of works
  static Semaphore mutex1 = new Semaphore(0); // creating a Semaphore To ImplementLogic
  static Semaphore mutex = new Semaphore(1); // Creating A Mutex
  static class Producer extends Thread {
    public void run() { // default run method of thread
      int counter = 1;
      try {
        while (true) {
          String threadName = Thread.currentThread().getName()
              + counter++; // counter is added to have the thread number being used

          mutex.acquire(); // Acquiring  Lock  before Producing so the consumer cannot consume.
          WorkingQueue.add(threadName);
          System.out.println("Producer is prdoucing producing: " + threadName);
          mutex.release(); // releasing After Production ;
          mutex1.release(); // relesing lock for consumer...so consumer can consume after production
          Thread.sleep(2000); // just to Reduce the Execution Speed
        }
      } catch (Exception e) { /*nothing */
      }
    }
  }
  static class Consumer extends Thread {
    String consumerName;
    public Consumer(String name) {
      this.consumerName = name;
    }
    public void run() {
      try {
        while (true) {
          mutex1.acquire(); /// Again Acquiring So no production while consuming
          mutex.acquire(); // Acquring Other consumers lock one consume at one time
          String result = "";
          for (String value : WorkingQueue) {
            result = value + ",";
          }
          System.out.println(consumerName + " consumes value: " + result
              + "Total Size working Queue Size " + WorkingQueue.size() + "\n");
          mutex.release(); // releasing lock for other consumers.
        }
      } catch (Exception e) {
      }
    }
    public static void main(String[] args) {
      Producer producer = new Producer();

      producer.start();
      Consumer c1 = new Consumer("Bill Gates");
      Consumer c2 = new Consumer("Jeff Bezoz");
      Consumer c3 = new Consumer("Mark Zukerberg");
      c1.start();
      c2.start();
      c3.start();
    }
  }
}

説明

上記のコードも一目瞭然ですが、この説明で混乱を解消できます。

Producer スレッドの内部

上記のプログラムを実行すると、producer スレッドが作成されます。そのスレッド内には、無期限に実行される while ループがあります。文字列 threadName は、スレッドの実行を表示するためだけのものです。オブジェクト mutex は、コンシューマスレッドが機能するためのロックを取得します。(ミューテックスの主な目的は、並行性を制御することです)。

その後、producer スレッドが機能するようになります。次に、このスレッドを本番用にリリースする必要があります。producer スレッドでは、consumerproducer の間の切り替えを処理するオブジェクトである mutex1 をリリースします。リリースされると、コンシューマーは消費を開始します。つまり、consumer スレッドが機能します。

Consumer スレッドの内部

consumer スレッドに入った直後に、mutex1 を取得して、消費中の生産を停止しました。ご覧のとおり、C1C2C3 という名前で 3つのコンシューマーを作成しました。1 人の消費者が一度に機能できるようにするために、mutex も取得しました。

その後、C1 が機能し、C2C3 が取得されます。完了すると、mutex が再びリリースされ、他のコンシューマーが機能できるようになります。

これは、ミューテックスが Java でどのように機能するかです。上記のプログラムを実行した後。使用されている producer スレッドの現在の数と、それを使用している consumer の名前が常に表示されます。

Java ミューテックスの例

プログラムの実行に伴い、サイズは増加し続けます。