Java 里有互斥吗?

在 Java 中是否有一个 Mutex 对象或者创建一个 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();
}

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

220145 次浏览

请看这一页: http://www.oracle.com/technetwork/articles/javase/index-140767.html

它有一个稍微不同的模式,这是(我认为)你正在寻找的:

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

在这种用法中,只有在 acquire()成功之后才调用 release()

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

Object someObject = ...;


synchronized (someObject) {
...
}

你可以在这里了解更多: 内部锁和同步

为了确保 Semaphore是二进制的,您只需要在创建信号量时确保传入的许可数为1。Javadocs有更多的解释。

每个对象的锁与 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。至于标准库,Semaphore 提供了所有这些功能以及更多功能。

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

原始文章中的错误是在 try 循环中设置了获取()调用。 下面是使用“二进制”信号量(Mutex)的正确方法:

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

我觉得你应该试试:

而信号量初始化:

Semaphore semaphore = new Semaphore(1, true);

还有你的 Runnable Implementation

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


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

没有人清楚地提到这一点,但是这种模式通常是 不适合信号灯。,原因是 任何线程可以释放一个信号量,但是你通常只需要 所有者线程那个 最初锁定,以便能够解锁。对于这个用例,在 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 源代码中的一个示例,您可以在其中看到这个模式的运行。

可重入锁具有支持公平性的额外好处。

只有在需要非所有权发布语义时才使用信号量。