我可以看到如何在Java中实现“标准”Semaphore类。但是,我不知道如何在Java中实现二进制信号量类。这种实现如何工作?我应该何时调用wake和notify方法来唤醒和停止信号量上的线程? 我明白什么是二进制信号量,但我不知道如何对它们进行编码。如何在Java中实现二进制信号量类?
编辑注:意识到我说“BINARY”信号量类。标准的Semaphore类我已经做了,我知道它是正确的,所以标准的Semaphore类对我不感兴趣。
我可以看到如何在Java中实现“标准”Semaphore类。但是,我不知道如何在Java中实现二进制信号量类。这种实现如何工作?我应该何时调用wake和notify方法来唤醒和停止信号量上的线程? 我明白什么是二进制信号量,但我不知道如何对它们进行编码。如何在Java中实现二进制信号量类?
编辑注:意识到我说“BINARY”信号量类。标准的Semaphore类我已经做了,我知道它是正确的,所以标准的Semaphore类对我不感兴趣。
我想你说的是互斥锁(或互斥锁)。如果是这样,你可以使用内部锁。这种在Java中的行为锁的互斥体,这意味着最多只有一个线程可以拥有锁:
synchronized (lock) {
// Access or modify shared state guarded by lock
}
如果锁是一个模拟对象,仅用于锁定使用。
编辑:
这是给你一个实现 - 它使用的零值表示未锁定状态非再进入的互斥锁类,以及一个代表锁定状态。
class Mutex implements Lock, java.io.Serializable {
// Our internal helper class
private static class Sync extends AbstractQueuedSynchronizer {
// Report whether in locked state
protected boolean isHeldExclusively() {
return getState() == 1;
}
// Acquire the lock if state is zero
public boolean tryAcquire(int acquires) {
assert acquires == 1; // Otherwise unused
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// Release the lock by setting state to zero
protected boolean tryRelease(int releases) {
assert releases == 1; // Otherwise unused
if (getState() == 0) throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
// Provide a Condition
Condition newCondition() { return new ConditionObject(); }
// Deserialize properly
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
// The sync object does all the hard work. We just forward to it.
private final Sync sync = new Sync();
public void lock() { sync.acquire(1); }
public boolean tryLock() { return sync.tryAcquire(1); }
public void unlock() { sync.release(1); }
public Condition newCondition() { return sync.newCondition(); }
public boolean isLocked() { return sync.isHeldExclusively(); }
public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
}
如果你需要知道你应该在哪里叫wait()
和notify()
,看看sun.misc.Unsafe#park()
。 ( - LockSupport < - 不安全的AbstractQueuedSynchronizer <)它的java.util.concurrent.locks包内使用。
希望这会有所帮助。
这里是直接从Java site
并发实用程序库,由Doug Lea领导的JSR-166是一个 专门发布的J2SE 5.0平台中的流行并发程序包。它提供了强大的高级线程结构,其中包括执行程序,它们是线程任务框架,线程安全的 队列,定时器,锁(包括原子的),以及其他 同步原语。
一个这样的锁是众所周知的信号量。信号量可以用于 ,与现在使用等待的方式相同,用于限制对代码块的访问。信号量更加灵活,并且还可以允许多个并发线程访问,并允许您在 获取它之前测试锁。以下示例仅使用一个信号量,也称为二进制信号量,即 。有关更多信息,请参阅java.util.concurrent包中的 。
final private Semaphore s= new Semaphore(1, true);
s.acquireUninterruptibly(); //for non-blocking version use s.acquire()
try {
balance=balance+10; //protected value
} finally {
s.release(); //return semaphore token
}
我认为,采用更高级别的摘要,例如Semaphore类的全部原因是,你不必叫低水平wait
/notify
。
是的,你可以。具有单一许可证的信号量是二进制信号量。他们控制对单一资源的访问。他们可以被看作是某种互斥/锁。
Semaphore binarySemaphore = new Semaphore(1);
下面是一个简单的实现我做了一个二进制信号:
public class BinarySemaphore {
private final Semaphore countingSemaphore;
public BinarySemaphore(boolean available) {
if (available) {
countingSemaphore = new Semaphore(1, true);
} else {
countingSemaphore = new Semaphore(0, true);
}
}
public void acquire() throws InterruptedException {
countingSemaphore.acquire();
}
public synchronized void release() {
if (countingSemaphore.availablePermits() != 1) {
countingSemaphore.release();
}
}
}
该实现二进制信号,你不能用计数信号,只有有一个许可证获得一个属性 - 多个呼叫释放仍将只留下一个资源。这个属性被提到here。
这是不安全的 - 只有release()是同步的,所以如果acquire并发运行释放,在if(countingSemaphore.availablePermits()!= 1)之后,以及调用释放之前,最终可能会出现意外的行为。此外,使获取同步不会工作,因为锁然后锁定,停止释放二进制信号量,停止应用程序。 –
@SamHeather我只是想着你说的话,如果非同步方法获取开始就像你在!= 1检查后说的那样,将没有可用的槽,并且内部的acquire-call会停止,并且线程会等待,上下文切换,另一个释放线程可以继续调用'countingSemaphore.release();' 只是想,如果这将是一个问题吗?我认为所有可能的请求线程都会卡在内核'countingSemaphore.acquire();'-call。你不这么认为吗? 同步'release()' - 方法只是避免了太多的空闲插槽。 – Dunstkreis
我有我自己的实施二进制信号在Java中的。
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* A binary semaphore extending from the Java implementation {@link Semaphore}.
* <p>
* This semaphore acts similar to a mutex where only one permit is acquirable. Attempts to acquire or release more than one permit
* are forbidden.
* <p>
* Has in {@link Semaphore}, there is no requirement that a thread that releases a permit must have acquired that permit. However,
* no matter how many times a permit is released, only one permit can be acquired at a time. It is advised that the program flow
* is such that the thread making the acquiring is the same thread making the release, otherwise you may end up having threads
* constantly releasing this semaphore, thus rendering it ineffective.
*
* @author Pedro Domingues
*/
public final class BinarySemaphore extends Semaphore {
private static final long serialVersionUID = -927596707339500451L;
private final Object lock = new Object();
/**
* Creates a {@code Semaphore} with the given number of permits between 0 and 1, and the given fairness setting.
*
* @param startReleased
* <code>true</code> if this semaphore starts with 1 permit or <code>false</code> to start with 0 permits.
* @param fairMode
* {@code true} if this semaphore will guarantee first-in first-out granting of permits under contention, else
* {@code false}
*/
public BinarySemaphore(boolean startReleased, boolean fairMode) {
super((startReleased ? 1 : 0), fairMode);
}
@Override
public void acquire(int permits) throws InterruptedException {
if (permits > 1)
throw new UnsupportedOperationException("Cannot acquire more than one permit!");
else
super.acquire(permits);
}
@Override
public void acquireUninterruptibly(int permits) {
if (permits > 1)
throw new UnsupportedOperationException("Cannot acquire more than one permit!");
else
super.acquireUninterruptibly(permits);
}
@Override
public void release() {
synchronized (lock) {
if (this.availablePermits() == 0)
super.release();
}
}
@Override
public void release(int permits) {
if (permits > 1)
throw new UnsupportedOperationException("Cannot release more than one permit!");
else
this.release();
}
@Override
public boolean tryAcquire(int permits) {
if (permits > 1)
throw new UnsupportedOperationException("Cannot acquire more than one permit!");
else
return super.tryAcquire(permits);
}
@Override
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException {
if (permits > 1)
throw new UnsupportedOperationException("Cannot release more than one permit!");
else
return super.tryAcquire(permits, timeout, unit);
}
}
告诉我,如果你发现代码中有任何错误,但到目前为止,它总是正常工作! :)
你有没有尝试过;以现有信号灯类的源代码,它会如何表现,如果它是只需要1。 – Scorpion
许可你看了(例如维基百科)的定义(二进制)信号量?你能解释为什么给出的答案(特别是Vikas的答案或亚历山大的更广泛的答案)是不够的?否则,你可以尝试解释用例(为了什么*目的*你需要二进制信号量/互斥量吗?) –