JavaRush /Java Blog /Random-JA /ミューテックス、モニター、セマフォの違いは何ですか

ミューテックス、モニター、セマフォの違いは何ですか

Random-JA グループに公開済み
こんにちは!JavaRush でマルチスレッドを勉強していると、「ミューテックス」と「モニター」という概念によく遭遇します。覗き込まずに、それらがどのように異なるのか答えられますか? :) ミューテックス、モニター、セマフォの違いは何ですか - 1できれば、うまくいきました!そうでない場合(そしてほとんどの場合、これが起こります) - 不思議ではありません。「ミューテックス」と「モニター」の概念は確かに関連しています。さらに、インターネット上の外部リソースでマルチスレッドに関する講義を読んだり、ビデオを見たりしていると、別の同様の概念である「セマフォ」に遭遇するでしょう。その機能も、モニターやミューテックスとほぼ同様です。したがって、これら 3 つの用語を理解し、いくつかの例を見て、最後にそれらが互いにどのように異なるのかを頭の中で整理しましょう :)

ミューテックス

ミューテックスは、スレッドを同期するための特別なオブジェクトです。これは Java のすべてのオブジェクトに「添付」されます - もうご存知のとおり :) 標準クラスを使用するか独自のクラスを作成したかは関係ありません。Catすべてのクラスのすべてのオブジェクトにはミューテックスがあります。「mutex」という名前は英語の「MUTual EXclusion」つまり「相互排除」に由来しており、これはその目的を完全に反映しています。前の講義の 1 つで述べたように、ミューテックスの役割は、特定の時点で 1 つのスレッドだけがオブジェクトにアクセスできるようにするメカニズムを提供することです。実生活におけるミューテックスのよく使われる例えは、「トイレの例」です。人がトイレに入るときは、内側からドアに鍵を掛けます。トイレは、複数のスレッドからアクセスできるオブジェクトとして機能します。トイレのドアの鍵がミューテックスの役割、外に並ぶ人の列がスレッドの役割です。ドアの鍵はトイレのミューテックスになっており、一度に 1 人だけが中に入ることができます。 つまり、共有リソースで動作できるスレッドは一度に 1 つだけです。他のスレッド (人) が占有されているリソースにアクセスしようとすると失敗します。ミューテックスにはいくつかの重要な機能があります。 まず、考えられる状態は「空き」と「ビジー」の 2 つだけです。これにより、その仕組みが理解しやすくなります。平行線は、ブール変数true/falseまたは 2 進数系 1/0 を使用して描画できます。 第二に、状態を直接制御することはできません。Java には、明示的にオブジェクトを取得し、そのミューテックスを取得し、それに必要なステータスを割り当てることを可能にするメカニズムはありません。つまり、次のようなことはできません。 Dogミューテックス、モニター、セマフォの違いは何ですか - 2

Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
したがって、オブジェクトのミューテックスを解放できません。Java マシンのみがそれに直接アクセスできます。プログラマは言語ツールを使用してミューテックスを操作します。

モニター

モニターは、ミューテックスへの追加の「アドオン」です。実際、モニターはプログラマにとって「見えない」コードの一部です。先ほどミューテックスについて話しましたが、簡単な例を示しました。

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...some logic available to all threads

       synchronized (obj) {

           //logic that is only available to one thread at a time
       }
   }
}
単語でマークされたコード ブロックではsynchronized、オブジェクトのミューテックスがキャプチャされますobj。さて、捕獲は起こりますが、「防御メカニズム」は正確にどのように達成されるのでしょうか? 他のスレッドは単語を見たときにsynchronizedブロック内に入れないのはなぜですか? 保護メカニズムを作成するのはモニターです。コンパイラは単語をsynchronizedいくつかの特別なコードに変換します。もう一度メソッドの例に戻りdoSomething()、それに追加してみましょう。

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...some logic available to all threads

       //logic that is only available to one thread at a time
       synchronized (obj) {

           /*выполнить важную работу, при которой доступ к an objectу
           должен быть только у одного потока*/
           obj.someImportantMethod();
       }
   }
}
コンパイラがこのコードを変換した後、プログラムの「内部」で何が起こるかは次のとおりです。

public class Main {

   private Object obj = new Object();

   public void doSomething() throws InterruptedException {

       //...some logic available to all threads

       //логика, которая одновременно доступна только для одного потока:
     
       /*до тех пор, пока мьютекс an object занят -
       любой другой поток (кроме того, который его захватил), спит*/
       while (obj.getMutex().isBusy()) {
           Thread.sleep(1);
       }

       //пометить мьютекс an object How занятый
       obj.getMutex().isBusy() = true;

       /*выполнить важную работу, при которой доступ к an objectу
       должен быть только у одного потока*/
       obj.someImportantMethod();

       //освободить мьютекс an object
       obj.getMutex().isBusy() = false;
   }
}
もちろん、この例は現実のものではありません。ここでは、Java のようなコードを使用して、Java マシン内で現時点で何が起こっているかを反映しようとしました。ただし、この疑似コードは、ブロック内のオブジェクトとスレッドで実際に何が起こっているのかsynchronized、そしてコンパイラがこの単語をプログラマには「見えない」いくつかのコマンドにどのように変換するのかをよく理解できます。基本的に、Java の監視は という単語を使用して表現されますsynchronized。最後の例で単語の代わりに表示されたすべてのコードがsynchronizedモニターです。

セマフォ

マルチスレッドを独学で勉強していると出てくるもう一つの言葉が「セマフォ」です。これが何なのか、またモニターやミューテックスとどのように異なるのかを見てみましょう。セマフォは、リソースへのアクセスを同期するための手段です。 その特徴は、同期メカニズムを作成するときにカウンターを使用することです。 カウンタは、共有リソースに同時にアクセスできるスレッドの数を示します。 ミューテックス、モニター、セマフォの違いは何ですか - 3Java のセマフォは、 クラス によって表されますSemaphore。セマフォ オブジェクトを作成するときは、次のコンストラクターを使用できます。

Semaphore(int permits)
Semaphore(int permits, boolean fair)
コンストラクターに渡します。
  • int permits— カウンターの初期値と最大値。つまり、共有リソースに同時にアクセスできるスレッドの数です。

  • boolean fair- スレッドがアクセスを受け取る順序を確立します。fair= trueの場合、待機中のスレッドへのアクセスは、要求された順序で許可されます。falseの場合、順序はスレッド スケジューラによって決定されます。

セマフォの使用の典型的な例は、ランチ哲学者問題です。
ミューテックス、モニター、セマフォの違いは何ですか - 4
理解を深めるために用語を少し簡略化します。昼食が必要な 5 人の哲学者がいると想像してください。同時に、テーブルが 1 つあり、同時に 2 人までがテーブルに座ることができます。私たちの使命は、すべての哲学者に食事を提供することです。どちらも空腹であってはなりませんし、テーブルに座ろうとするときにお互いを「ブロック」してはいけません (デッドロックを回避する必要があります)。哲学者のクラスは次のようになります。

class Philosopher extends Thread {

   private Semaphore sem;

   // поел ли философ
   private boolean full = false;

   private String name;

   Philosopher(Semaphore sem, String name) {
       this.sem=sem;
       this.name=name;
   }

   public void run()
   {
       try
       {
           // если философ еще не ел
           if (!full) {
               //Запрашиваем у семафора разрешение на выполнение
               sem.acquire();
               System.out.println (name + " садится за стол");

               // философ ест
               sleep(300);
               full = true;

               System.out.println (name + " поел! Он выходит из-за стола");
               sem.release();

               // философ ушел, освободив место другим
               sleep(300);
           }
       }
       catch(InterruptedException e) {
           System.out.println ("What-то пошло не так!");
       }
   }
}
プログラムを実行するコードは次のとおりです。

public class Main {

   public static void main(String[] args) {

       Semaphore sem = new Semaphore(2);
       new Philosopher(sem,"Сократ").start();
       new Philosopher(sem,"Платон").start();
       new Philosopher(sem,"Аристотель").start();
       new Philosopher(sem,"Фалес").start();
       new Philosopher(sem,"Пифагор").start();
   }
}
同時に 2 人の哲学者だけが食事ができるという条件を満たすために、カウント 2 のセマフォを作成しました。つまり、このクラスは!Philosopherから継承されているため、同時に動作できるスレッドは 2 つだけです。クラスとThreadメソッドはその権限カウンターを制御します。このメソッドは、セマフォからリソースにアクセスする許可を要求します。カウンタ > 0 の場合、権限が付与され、カウンタは 1ずつ減分されます。メソッドは、以前に付与された権限を「解放」し、それをカウンタに返します (セマフォの許可カウンタを 1 ずつインクリメントします)。プログラムを実行すると何が得られるでしょうか? 問題は解決しましたか? 哲学者たちは順番を待ちながら戦うのでしょうか? :) これは私たちが受け取ったコンソール出力です: ソクラテスはテーブルに座ります。 プラトンは ソクラテスが食べたテーブルに座ります。彼はテーブルを離れました。プラトンは食べました!彼はテーブルを去り、アリストテレスはテーブルに座り、ピタゴラスはアリストテレスが食べた テーブルに座ります 。彼はピタゴラスが食べたテーブルを離れました。彼はテーブルを離れ、 タレスはタレスが食べていたテーブルに座りました 彼はテーブルを離れました。 私たちは成功しました! そして、タレスは一人で食事をしなければなりませんでしたが、彼は私たちに怒っていないと思います:) ミューテックスとセマフォの間にいくつかの類似点があることに気づいたかもしれません。 一般に、これらの目的は同じであり、リソースへのアクセスを同期することです。 唯一の違いは、オブジェクトのミューテックスは一度に 1 つのスレッドによってのみ取得できるのに対し、セマフォの場合はスレッド カウンターが使用され、複数のスレッドが一度にリソースにアクセスできることです。そして、これは単なる偶然の類似ではありません:) 実際、ミューテックスは単一の場所のセマフォです。つまり、カウンタが最初に 1 に設定されているセマフォです。そのカウンタは 1 (「フリー」) と 0 (「ビジー」) の 2 つの値しか持てないため、「バイナリ セマフォ」とも呼ばれます。それだけです!ご覧のとおり、すべてはそれほど混乱していないことがわかりました :) さて、インターネットでマルチスレッドのトピックをさらに詳しく調べたい場合は、概念をナビゲートするのが少し簡単になります。次のレッスンでお会いしましょう! acquire()release()Semaphoreacquire()release()ミューテックス、モニター、セマフォの違いは何ですか - 5
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION