我可以看到如何用Java实现“标准”信号量类。但是,我无法看到如何在Java中实现二进制信号量类。这种实施如何运作?我何时应该唤醒唤醒并通知方法唤醒和停止信号量上的线程? 我理解二进制信号量是什么,但我不知道如何编码它们。
编辑注意:意识到我说的是“BINARY”信号量类。我已经做过标准的Semaphore类,我知道它是正确的,所以标准的Semaphore类对我不感兴趣。
答案 0 :(得分:4)
这是我为二进制信号量做的一个简单实现:
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();
}
}
}
这个实现有一个二进制信号量的属性,你无法计算只有一个许可证的信号量 - 多次调用release仍然只剩下一个资源。提到此属性here。
答案 1 :(得分:3)
我认为你在谈论互斥锁(或互斥锁)。如果是这样,您可以使用内部锁。 Java中的这种锁充当互斥锁,这意味着最多只有一个线程拥有锁:
synchronized (lock) {
// Access or modify shared state guarded by lock
}
其中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()
。它在java.util.concurrent.locks包中使用(AbstractQueuedSynchronizer< - LockSupport< - Unsafe)。
希望这有帮助。
答案 2 :(得分:2)
这是直接来自Java site
由Doug Lea在JSR-166中领导的并发实用程序库是一个 将流行的并发包特别发布到J2SE 5.0中 平台。它提供强大的高级线程构造, 包括执行程序,它是一个线程任务框架,线程安全 队列,计时器,锁(包括原子锁)和其他 同步原语。
一个这样的锁是众所周知的信号量。信号量可用于 与现在使用wait的方式相同,限制对块的访问 码。信号量更灵活,也可以允许多种信号量 并发线程访问,以及允许您在之前测试锁 获得它。以下示例也仅使用一个信号量 称为二进制信号量。请参阅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
。
答案 3 :(得分:1)
是的,你可以。具有单个许可证的信号量是二进制信号量。它们控制对单个资源的访问。它们可以被视为某种互斥锁。
Semaphore binarySemaphore = new Semaphore(1);
答案 4 :(得分:1)
也许使用AtomicBoolean实现它是一个好主意。 如果不是,请告诉我。
import java.util.concurrent.atomic.AtomicBoolean;
public class BinarySemaphore {
private final AtomicBoolean permit;
public BinarySemaphore() {
this(true);
}
/**
* Creates a binary semaphore with a specified initial state
*/
public BinarySemaphore(boolean permit) {
this.permit = new AtomicBoolean(permit);
}
public void acquire() {
boolean prev;
do {
prev = tryAcquire();
} while (!prev);
}
public boolean tryAcquire() {
return permit.compareAndSet(true, false);
}
/**
* In any case, the permit was released
*/
public void release() {
permit.set(true);
}
public boolean available(){
return permit.get();
}
}
答案 5 :(得分:0)
您可以查看Semaphore类的Java实现的源代码(或者直接使用它?)
答案 6 :(得分:0)
我在Java中有自己的 Binary Semaphore 实现。
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);
}
}
请告诉我你是否在代码中发现了任何错误,但到目前为止它总能正常工作! :)
答案 7 :(得分:0)