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

上面的代码是否可以确保信号量是二进制的?


在javadoc中查找java.util.concurrent.locks.AbstractQueuedSynchronizer。它有一个如何编写Mutex类的示例。-dbednar

您是否凭经验发现了这种行为?这样的实现是否真的对一个1许可信号量执行release()会增加一个额外的许可,即使它当前持有另一个许可呢?
异想天开

Answers:



133

Java中的任何对象都可以使用synchronized块作为锁。当发生异常时,这也将自动照顾释放锁。

Object someObject = ...;

synchronized (someObject) {
  ...
}

您可以在此处阅读有关此内容的更多信息:内部锁和同步


非常有用的购买,我想使用信号灯。
Noam Nevo

11
@Noam:只需将代码与semaphore和与进行比较synchronized,您将看到可读性更好,更不易出错的代码。
弗拉德

17
如果希望以其他方法(例如transaction.begin(); transaction.commit())释放锁,则不能使用synced关键字。
Hosam Aly 2014年

并且它不是面向对象的
。.

还应考虑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 :"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 2015年

3
这是一个递归互斥体,将允许从同一线程进行多次重新锁定,这可能会引起问题。一个“真”基本互斥体(非递归,C ++样式)一次只能允许一个锁。如果将行更改为private final ReentrantLock _mutex = ...,则可以使用getHoldCount()返回线程重新锁定的次数。(您可以应用a Condition来防止这种情况。请参阅API。)
EntangledLoops 2015年

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

卢布:那么lockReentrantLock一个mutex?我不知道为什么mutexbinary semaphore并且被视为等同于同一实体。 Semaphore可以通过任何线程释放,因此可能无法保证守卫critical 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/…的说法: “不要求释放许可证的线程必须已经通过调用Acquisition获得了许可证。正确使用信号量是通过应用程序中的编程约定建立。” 如果获取引发异常,则最终版本中的释放将错误地释放许可证。此线程中的其他示例显示了正确的流程。
布伦特K.19年

3

原始帖子中的错误是在try循环内设置了acquire()调用。这是使用“二进制”信号量(Mutex)的正确方法:

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

1

为确保a Semaphore为二进制,您只需要确保在创建信号量时将允许的数量传递为1。在Javadoc中有详细说明一下。


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,但是您可以在Mutex.java中找到Mutext实现。至于标准库,Semaphore提供了所有这些功能以及更多其他功能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.