无锁解决方案(?)
我遇到了同样的问题,但是我想要一个不使用锁的解决方案。
问题:我最多只有一个线程从队列中消耗。多个生产者线程不断插入队列中,并且需要在等待时通知使用者。该队列是无锁的,因此使用锁进行通知会导致生产者线程不必要的阻塞。每个生产者线程都需要先获取锁,然后才能通知正在等待的使用者。我相信我想出了使用LockSupport
和的无锁解决方案AtomicReferenceFieldUpdater
。如果JDK中存在无锁屏障,则找不到它。双方CyclicBarrier
并CoundDownLatch
使用从我能找到的内部锁定。
这是我的缩写代码。只需清楚一点,此代码将只允许一个线程等待。通过使用某种类型的原子集合来存储多个所有者(ConcurrentMap
可以工作),可以对其进行修改以允许多个等待者/消费者。
我已经使用此代码,它似乎可以工作。我没有对其进行广泛的测试。我建议您LockSupport
在使用前阅读文档。
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.concurrent.locks.LockSupport;
public class SignalBarrier {
@SuppressWarnings("unused")
private volatile Thread _owner;
private static final AtomicReferenceFieldUpdater<SignalBarrier, Thread> ownerAccess =
AtomicReferenceFieldUpdater.newUpdater(SignalBarrier.class, Thread.class, "_owner");
public SignalBarrier() {
_owner = null;
}
public void signal() {
Thread t = ownerAccess.getAndSet(this, null);
if (t != null) {
LockSupport.unpark(t);
}
}
public void await() throws InterruptedException {
Thread t = Thread.currentThread();
if (!ownerAccess.compareAndSet(this, null, t)) {
throw new IllegalStateException("A second thread tried to acquire a signal barrier that is already owned.");
}
LockSupport.park(this);
ownerAccess.compareAndSet(this, t, null);
if (t.isInterrupted())
throw new InterruptedException();
}
public long awaitNanos(long timeout) throws InterruptedException {
if (timeout <= 0)
return 0;
Thread t = Thread.currentThread();
if (!ownerAccess.compareAndSet(this, null, t)) {
throw new IllegalStateException("A second thread tried to acquire a signal barrier is already owned.");
}
long start = System.nanoTime();
LockSupport.parkNanos(this, timeout);
ownerAccess.compareAndSet(this, t, null);
long stop = System.nanoTime();
if (t.isInterrupted())
throw new InterruptedException();
return Math.max(timeout - stop + start, 0L);
}
}
为了给出模糊的用法示例,我将采用james large的示例:
SignalBarrier barrier = new SignalBarrier();
使用者线程(单数,而不是复数!):
try {
while(!conditionIsTrue()) {
barrier.await();
}
doSomethingThatRequiresConditionToBeTrue();
} catch (InterruptedException e) {
handleInterruption();
}
生产者线程:
doSomethingThatMakesConditionTrue();
barrier.signal();