122

java中是否有互斥对象或创建方法?我问是因为用 1 个许可初始化的信号量对象对我没有帮助。想想这个案例:

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

上面的代码会确保信号量是二进制的吗?

4

8 回答 8

141

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

Object someObject = ...;

synchronized (someObject) {
  ...
}

您可以在此处阅读有关此内容的更多信息:Intrinsic Locks and Synchronization

于 2011-03-13T17:25:54.467 回答
121

请参阅此页面: http ://www.oracle.com/technetwork/articles/javase/index-140767.html

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

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

在这种用法中,您仅release()在成功后调用acquire()

于 2011-03-13T17:25:50.450 回答
32

没有人明确提到这一点,但这种模式通常不适合信号量。原因是任何线程都可以释放信号量,但您通常只希望最初锁定的所有者线程能够解锁。对于这个用例,在 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 源代码中的一个示例,您可以在其中看到此模式的实际效果。

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

仅当您需要非所有权释放语义时才使用信号量。

于 2017-10-03T14:51:38.593 回答
30
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();
于 2012-09-20T10:13:53.870 回答
6

我认为你应该尝试:

信号量初始化时:

Semaphore semaphore = new Semaphore(1, true);

在你的Runnable Implementation

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

} 
catch (Exception e) 
{
// Logging
}
finally
{
   semaphore.release(1);
}
于 2015-04-04T11:50:39.643 回答
3

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

semaphore.acquire();
try {
   //do stuff
} catch (Exception e) {
   //exception stuff
} finally {
   semaphore.release();
}
于 2013-03-01T05:28:23.820 回答
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();
} 

目前, 中没有这样的类,但您可以在Mutex.javajava.util.concurrent中找到 Mutext 实现。至于标准库,Semaphore 提供了所有这些功能等等。

于 2012-03-12T14:57:11.013 回答
0

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

于 2011-03-13T18:50:24.020 回答