Javaにミューテックスはありますか?


110

JavaのMutexオブジェクトまたはそれを作成する方法はありますか?1つの許可で初期化されたSemaphoreオブジェクトが役に立たないので、私は尋ねています。このケースを考えてみましょう:

try {
   semaphore.acquire();
   //do stuff
   semaphore.release();
} catch (Exception e) {
   semaphore.release();
}

最初の取得で例外が発生した場合、catchブロックでの解放により許可が増加し、セマフォはバイナリセマフォではなくなります。

正しい方法はありますか?

try {
   semaphore.acquire();
   //do stuff
} catch (Exception e) {
   //exception stuff
} finally {
   semaphore.release();
}

上記のコードはセマフォがバイナリであることを保証しますか?


javadocでjava.util.concurrent.locks.AbstractQueuedSynchronizerを確認してください。Mutexクラスの記述方法の例があります。-dbednar
joe

この動作を実験的に見つけましたか?1許可のセマフォでrelease()を実行するような実装は、現在別の許可を保持している場合でも、本当に追加の許可を追加しますか?
Whimusical

回答:


112

このページを参照してください:http : //www.oracle.com/technetwork/articles/javase/index-140767.html

それはあなたが探しているもの(私は思う)であるわずかに異なるパターンを持っています:

try {
  mutex.acquire();
  try {
    // do something
  } finally {
    mutex.release();
  }
} catch(InterruptedException ie) {
  // ...
}

この使用法ではrelease()、成功した後にのみ呼び出しますacquire()


133

Javaのすべてのオブジェクトは、synchronizedブロックを使用してロックとして使用できます。これにより、例外が発生したときにロックが自動的に解放されます。

Object someObject = ...;

synchronized (someObject) {
  ...
}

詳細については、こちらをご覧ください:組み込みロックと同期


セマフォを使いたかったのでとても助かります。
Noam Nevo

11
@Noam:コードをセマフォおよびと比較するだけでsynchronized、読みやすく、エラーが発生しにくいものがわかります。
Vlad

17
別の方法(などtransaction.begin(); transaction.commit())でロックを解放する予定がある場合は、synchronizedキーワードを使用できません。
Hosam Aly 2014年

オブジェクト指向ではありません。低レベルの同期の多く
anshulkatta

また、に見えるsomeObject.wait(timeout)し、someObject.notify()あなたがこの回答のコードを見ている間。
ダニエルF

25
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


private final Lock _mutex = new ReentrantLock(true);

_mutex.lock();

// your protected code here

_mutex.unlock();

5
これは、すでに提供されているソリューションよりどのように優れていますか?元の質問者が抱えていた問題をどのように解決しますか?
マーティン、

@Martin:"Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements."、from:docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/… ...ポイントはありますが。Argvの答えは、これらの操作を図示または説明していません。
FrustratedWithFormsDesigner 2015年

3
これは、同じスレッドからの複数の再ロックを可能にする再帰的なmutexであり、問​​題になる可能性があります。「真の」基本的なmutex(非再帰的、C ++スタイル)では、一度に1つのロックしか許可されません。行をprivate final ReentrantLock _mutex = ...に変更すると、getHoldCount()を使用してスレッドの再ロック数を返すことができます。(Conditionこれを防ぐためにa を適用できます。APIを参照してください。)
EntangledLoops '10 / 11/15

16

誰もこれについて明確に述べたことはありませんが、この種のパターンは通常、セマフォには適していません。その理由は、どのスレッドもセマフォを解放できるからです。通常は、最初にロックされてた所有者のスレッドだけがロックを解除できるようにする必要があります。この使用例では、Javaでは通常、次のように作成できるReentrantLocksを使用します。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

private final Lock lock = new ReentrantLock(true);

そして、使用の通常の設計パターンは次のとおりです。

  lock.lock();
  try {
      // do something
  } catch (Exception e) {
      // handle the exception
  } finally {
      lock.unlock();
  }

ここではあなたがアクションでこのパターンを見ることができますJavaのソースコードの例です。

再入可能ロックには、公平性をサポートするという追加の利点があります。

非所有権解放のセマンティクスが必要な場合にのみ、セマフォを使用してください。


5
実際、これはこの質問に対する(唯一の)正解でなければなりません。セマフォと相互排他ロックの違いの明確な説明。でセマフォを使用することcount=1は、相互排他ロックではありません。
カイワ

3
誰かが指摘してくれてうれしい。リソースへの排他的アクセスについては、ミューテックスが適しています。バイナリセマフォはミューテックスではありません。セマフォはシグナリングメカニズムとしてより使用されるべきです。
Shivam Tripathi

ルーブル:だからであるlock例えばReentrantLockaはmutex?私がなぜわからないmutexbinary semaphore同じエンティティであることを同一視取られています。 Semaphoreどのスレッドでも解放できるため、保護が保証されない場合がありcritical sectionます。何かご意見は?
CuriousMind

@海花:私はあなたの考えに共鳴します。この答えは重要な違いをもたらします
CuriousMind

6

私はあなたが試してみるべきだと思います:

セマフォの初期化中:

Semaphore semaphore = new Semaphore(1, true);

そしてあなたの Runnable Implementation

try 
{
   semaphore.acquire(1);
   // do stuff

} 
catch (Exception e) 
{
// Logging
}
finally
{
   semaphore.release(1);
}

これは私がやった方法ですが、これが進むべき道かどうかはよくわかりません。
デタッチ

1
docs.oracle.com/javase/7/docs/api/java/util/concurrent/…によれば、「permitを解放するスレッドが、acquireを呼び出してそのパーミットを取得している必要はありません。セマフォの正しい使用法は、アプリケーションのプログラミング規約によって確立されました。」取得が例外をスローする場合、finallyのリリースは許可を誤ってリリースします。このスレッドの他の例は、正しいフローを示しています。
ブレントK.

3

元の投稿の間違いは、tryループ内にセットされたacquire()呼び出しです。以下は、「バイナリ」セマフォ(Mutex)を使用するための正しいアプローチです。

semaphore.acquire();
try {
   //do stuff
} catch (Exception e) {
   //exception stuff
} finally {
   semaphore.release();
}


1

各オブジェクトのロックは、Mutex /セマフォの設計と少し異なります。たとえば、前のノードのロックを解除して次のノードをキャプチャすることで、リンクされたノードのトラバースを正しく実装する方法はありません。しかし、ミューテックスを使用すると、簡単に実装できます。

Node p = getHead();
if (p == null || x == null) return false;
p.lock.acquire();  // Prime loop by acquiring first lock.
// If above acquire fails due to interrupt, the method will
//   throw InterruptedException now, so there is no need for
//   further cleanup.
for (;;) {
Node nextp = null;
boolean found;
try { 
 found = x.equals(p.item); 
 if (!found) { 
   nextp = p.next; 
   if (nextp != null) { 
     try {      // Acquire next lock 
                //   while still holding current 
       nextp.lock.acquire(); 
     } 
     catch (InterruptedException ie) { 
      throw ie;    // Note that finally clause will 
                   //   execute before the throw 
     } 
   } 
 } 
}finally {     // release old lock regardless of outcome 
   p.lock.release();
} 

現在、中にはそのようなクラスがありませんjava.util.concurrentが、あなたはここでMutextの実装を見つけることができMutex.javaを。標準ライブラリに関しては、セマフォはこのすべての機能を提供します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.