Java에 Mutex가 있습니까?


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();
}

위의 코드는 세마포어가 바이너리인지 확인합니까?


java.util.concurrent.locks.AbstractQueuedSynchronizer에 대한 javadoc을 살펴보십시오. Mutex 클래스를 작성하는 방법에 대한 예제가 있습니다. -dbednar
joe

이 행동을 경험적으로 알아 냈습니까? 1 허가 세마포어에서 release ()를 실행하면 현재 다른 허가를 보유하고 있더라도 추가 허가가 추가되는 구현입니까?
Whimusical

답변:



133

Java의 모든 객체는 synchronized블록을 사용하여 잠금으로 사용할 수 있습니다 . 또한 예외가 발생하면 자동으로 잠금 해제를 처리합니다.

Object someObject = ...;

synchronized (someObject) {
  ...
}

이에 대한 자세한 내용은 여기에서 읽을 수 있습니다. 고유 잠금 및 동기화


세마포어를 사용하고 싶었습니다.
Noam Nevo 2011 년

11
@Noam : 코드를 세마포어와 비교하면 synchronized무엇이 더 읽기 쉽고 오류가 덜 발생하는지 알 수 있습니다.
Vlad 2011 년

17
다른 방법 (예 :)으로 잠금을 해제하려는 경우 동기화 된 키워드를 사용할 수 없습니다 transaction.begin(); transaction.commit().
Hosam Aly 2014 년

그리고 그것의 객체 지향적이지 않습니다. 그것의 많은 저수준 동기화
anshulkatta dec.

또한 조사 someObject.wait(timeout)someObject.notify()이 대답의 코드를 찾고있다.
Daniel 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

@Martin : "Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements.", 출처 : docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/… ...하지만 요점이 있습니다. Argv의 대답은 이러한 작업을 설명하거나 설명하지 않습니다.
FrustratedWithFormsDesigner

3
이것은 문제가 될 수있는 동일한 스레드에서 여러 번의 재 잠금을 허용하는 재귀 적 뮤텍스입니다. "true", 기본 뮤텍스 (비 재귀, C ++ 스타일)는 한 번에 하나의 잠금 만 허용합니다. 행을로 변경 private final ReentrantLock _mutex = ...하면 getHoldCount () 를 사용 하여 스레드 재 잠금 횟수를 반환 할 수 있습니다. ( Condition이를 방지하기 위해 a 를 적용 할 수 있습니다 . API 참조 .)
EntangledLoops

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();
  }

다음 은이 패턴이 작동하는 것을 볼 수있는 자바 소스 코드의 예입니다.

재진입 잠금에는 공정성을 지원하는 추가 이점이 있습니다.

비 소유권 릴리스 의미 체계가 필요한 경우에만 세마포어를 사용하십시오.


5
사실 이것은이 질문에 대한 (유일한) 정답이어야합니다. 세마포어와 상호 배제 잠금의 차이점에 대한 명확한 설명. 세마포어를 함께 사용하는 count=1것은 상호 배제 잠금이 아닙니다.
Kaihua

3
누군가가 지적한 것을 기쁘게 생각합니다. 리소스 뮤텍스에 대한 배타적 액세스는 갈 길입니다. 이진 세마포어는 뮤텍스가 아니므로 신호 메커니즘으로 세마포어를 더 많이 사용해야합니다.
Shivam Tripathi

루블 : 그래서는 lock예를 들어 ? 그 이유를 모르겠습니다 와 같은 개체로 동일시 취해지고있다. 어떤 실로도 풀릴 수 있으므로 가드가 보장되지 않을 수 있습니다 . 이견있는 사람? ReentrantLockmutexmutexbinary semaphoreSemaphorecritical section
CuriousMind

@Kaihua : 나는 당신의 생각에 공감합니다. 이 답변은 주요 차이점을 가져옵니다
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/… 에 따르면 "허가를 해제하는 스레드가 취득을 호출하여 허가를 취득해야한다는 요구 사항은 없습니다. 세마포어의 올바른 사용법은 다음과 같습니다. 응용 프로그램의 프로그래밍 규칙에 의해 설정됩니다. " 취득에서 예외가 발생하면 finally의 릴리스가 허가를 잘못 해제합니다. 이 스레드의 다른 예는 올바른 흐름을 보여줍니다.
Brent K.

3

원래 게시물의 실수는 try 루프 내부에 설정된 acquire () 호출입니다. 다음은 "이진"세마포어 (Mutex)를 사용하는 올바른 방법입니다.

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


1

각 개체의 잠금은 Mutex / Semaphore 디자인과 약간 다릅니다. 예를 들어, 이전 노드의 잠금을 해제하고 다음 노드를 캡처하여 연결된 노드 순회를 올바르게 구현할 방법이 없습니다. 그러나 뮤텍스를 사용하면 쉽게 구현할 수 있습니다.

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을 . 표준 라이브러리의 경우 Semaphore는이 모든 기능과 그 이상을 제공합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.