回答:
セマフォはカウントできますが、ミューテックスは1までしかカウントできません。
クライアント接続を受け入れる実行中のスレッドがあるとします。このスレッドは、10クライアントを同時に処理できます。次に、新しいクライアントはそれぞれ、セマフォを10に達するまで設定します。セマフォに10個のフラグがある場合、スレッドは新しい接続を受け入れません。
ミューテックスは通常、ものを保護するために使用されます。10個のクライアントがシステムの複数の部分にアクセスできるとします。次に、システムの一部をミューテックスで保護して、1つのクライアントがそのサブシステムに接続されているとき、他の誰もアクセスできないようにすることができます。この目的にもセマフォを使用できます。mutexは「相互排除セマフォ」です。
ReentrantLock
。これらはすべて再帰的です。私は非再帰的ミューテックスの「実際の」例を知りません(教科書でしか見たことがないので)とは考えませんでした。
残念ながら、セマフォとミューテックスの最も重要な違いを見逃している人がいます。「所有権」の概念。
セマフォには所有権の概念がないため、どのスレッドでもセマフォを解放できます(これにより、多くの問題が発生する可能性がありますが、「死の検出」に役立ちます)。一方、ミューテックスには所有権の概念があります(つまり、取得したミューテックスのみを解放できます)。
並行システムを安全にプログラミングするには、所有権が非常に重要です。私は常にセマフォよりもミューテックスを使用することをお勧めします(ただし、パフォーマンスに影響があります)。
ミューテックスは、優先度の継承(優先度の逆転の問題に役立つ)と再帰(1種類のデッドロックを排除する)もサポートします。
「バイナリ」セマフォと「カウント/一般」セマフォがあることも指摘する必要があります。Javaのセマフォはカウンティングセマフォであるため、1より大きい値で初期化できます(指摘されているように、ミューテックスは概念的に1しかカウントできません)。これの有用性は他の投稿で指摘されています。
まとめると、管理するリソースが複数ない限り、セマフォよりもミューテックスを常にお勧めします。
ミューテックスは基本的に相互排除です。一度に1つのスレッドのみがリソースを取得できます。1つのスレッドがリソースを取得すると、リソースを所有するスレッドが解放されるまで、他のスレッドはリソースを取得できません。リソースの取得を待機しているすべてのスレッドがブロックされます。
セマフォは、実行中のスレッドの数を制御するために使用されます。リソースの固定セットがあります。リソースカウントは、スレッドが所有するたびに減少します。セマフォカウントが0に達すると、他のスレッドはリソースを取得できなくなります。スレッドは、リソース解放を所有する他のスレッドまでブロックされます。
つまり、主な違いは、一度にリソースを取得できるスレッドの数です。
セマフォはカウント同期メカニズムですが、ミューテックスはそうではありません。
この質問には関連する回答と公式のJavaガイダンスへのリンクがあります。Javaにミューテックスはありますか?
セマフォ:
カウントするセマフォ。概念的には、セマフォは一連の許可を保持します。
acquire()
許可が得られるまで、必要に応じて各ブロックを行い、許可を取得します。それぞれrelease()
が許可を追加し、潜在的にブロッキング取得者を解放します。ただし、実際の許可オブジェクトは使用されません。セマフォは、利用可能な数のカウントを保持し、それに応じて動作します。
セマフォは、いくつかの(物理的または論理的)リソースにアクセスできるスレッドの数を制限するためによく使用されます。
Javaには組み込みのMutex APIがありません。ただし、バイナリセマフォとして実装できます。
1に初期化され、使用可能な許可が1つだけになるように使用されるセマフォは、相互排他ロックとして機能できます。これは2つの状態しかないため、一般的にバイナリセマフォとして知られています。1つのパーミットが使用可能か、またはゼロのパーミットが使用可能です。
この方法で使用すると、バイナリセマフォには、多くのLock実装とは異なり、所有者以外のスレッドが「ロック」を解放できるという特性があります(セマフォには所有権の概念がないため)。。これは、デッドロック回復などの一部の特殊なコンテキストで役立ちます。
だから、重要な相違点セマフォとミューテックスの間:
セマフォは、許可されたリソースにアクセスするスレッドの数を制限します。Mutexでは、リソースにアクセスできるスレッドは1つだけです。
セマフォを所有するスレッドはありません。スレッドはacquire()
とrelease()
メソッドを呼び出すことで、許可の数を更新できます。mutexは、ロックを保持しているスレッドによってのみロック解除されます。
mutexが条件変数と共に使用される場合、暗黙のブラケットがあり、プログラムのどの部分が保護されているかは明らかです。これは、セマフォの場合に必ずしも当てはまりません。これは、並行プログラミングのgo toと呼ばれる可能性があります。強力ですが、非構造化された不確定な方法で使用するのは簡単です。
同期対象のセマフォ古典的な信号機を実装します。信号機は、カウンターが共有するリソースへのアクセスを制御します。カウンターがゼロより大きい場合、アクセスが許可されます。ゼロの場合、アクセスは拒否されます。カウンターは、共有リソースへのアクセスを許可するアクセス許可をカウントします。次に、リソースにアクセスするには、スレッドが信号機から許可を受け取る必要があります。一般に、信号機を使用するために、共有リソースにアクセスしたいスレッドは許可を取得しようとします。信号数がゼロより大きい場合、スレッドは許可を取得し、信号数は減分されます。それ以外の場合、スレッドは許可を得るまでロックされます。スレッドが共有リソースにアクセスする必要がなくなると、スレッドは許可を解放するため、信号数が増加します。許可を待っている別のスレッドがある場合、その時に許可を取得します。JavaのSemaphoreクラスはこのメカニズムを実装しています。
セマフォには2つのビルダーがあります。
Semaphore(int num)
Semaphore(int num, boolean come)
numは、許可の初期カウントを指定します。次に、numは、特定の時間に共有リソースにアクセスできるスレッドの数を指定します。numが1の場合、一度に1つのスレッドでリソースにアクセスできます。comeをtrueに設定することで、待機しているスレッドに、要求された順序でアクセス許可が付与されることを保証できます。
あなたは比類のないものを比較します、技術的にはセマフォとそれが意味をなさないミューテックスの間に違いはありません。Mutexは、アプリケーションロジック内の任意の名前と同様に重要な名前です。つまり、セマフォを「1」に初期化します。これは、一般に、リソースまたは保護された変数を保護して相互排除を保証するために使用されます。