我试图创建一个SingleBlockingQueue<T>
同步器,允许一个线程offer()
一个元素到它,另一个线程将take()
它。 {1}}中一次只保留一个T
元素,如果前一个元素正在等待获取线程SingleBlockingQueue<T>
,则offer()
上的推送线程被阻塞。推送线程将继续推送项目,直到它调用take()
,并且当setComplete()
为假时,获取线程将继续调用take()
。如果正在等待元素,则获取线程将阻塞。
这是我到目前为止所拥有的同步器。
isComplete()
以下是Kotlin的一个用法示例
import java.util.concurrent.atomic.AtomicBoolean;
public final class SingleBlockingQueue<T> {
private volatile T value;
private final AtomicBoolean isComplete = new AtomicBoolean(false);
private final AtomicBoolean isPresent = new AtomicBoolean(false);
public void offer(T value) throws InterruptedException {
while (isPresent.get()) {
this.wait();
}
this.value = value;
synchronized(this) {
this.notifyAll();
}
}
public boolean isComplete() {
return !isPresent.get() && isComplete.get();
}
public void setComplete() {
isComplete.set(true);
}
public T take() throws InterruptedException {
while (!isPresent.get()) {
this.wait();
}
T returnValue = value;
isPresent.set(false);
synchronized(this) {
this.notifyAll();
}
return returnValue;
}
}
然而,我收到了一个错误,此时我有点过头了。由于RxJava,我很久没有制作同步器了。我究竟做错了什么?
val queue = SingleBlockingQueue<Int>()
thread {
for (i in 1..1000) {
queue.offer(i)
}
queue.setComplete()
}
thread {
while (!queue.isComplete) {
println(queue.take())
}
}
Thread.sleep(100000)
答案 0 :(得分:2)
您不需要自己实施,可以使用SynchronousQueue
参考文献:
http://tutorials.jenkov.com/java-util-concurrent/synchronousqueue.html
SynchronousQueue类实现BlockingQueue接口。 有关该接口的详细信息,请阅读BlockingQueue文本。
SynchronousQueue是一个只能包含单个元素的队列 内部。将元素插入队列的线程被阻止 直到另一个线程从队列中获取该元素。同样,如果一个 线程尝试获取元素,当前不存在任何元素, 该线程被阻塞,直到一个线程插入一个元素 队列中。
答案 1 :(得分:1)
正如其他人所指出的那样,您可以使用SynchronousQueue
中的现有实现。
如果你想要实现自己的,你只需要确保对wait()
块的调用是在synchronized
块内。
不幸的是,我认为原始代码中的isComplete()
/ setComplete()
机制会受到竞争条件的影响,因为在setComplete()
返回后isComplete()
可能会被调用false
1}}以及在阅读线程执行take()
之前或之后。这可能会使读取线程挂起。
public final class SingleBlockingQueue<T> {
private final Object lock = new Object();
private T value;
private boolean present = false;
public void offer(T value) throws InterruptedException {
synchronized (lock) {
while (present)
lock.wait();
this.value = value;
present = true;
lock.notifyAll();
}
}
public T take() throws InterruptedException {
synchronized (lock) {
while (!present)
lock.wait();
T returnValue = value;
value = null; // Should release reference
present = false;
lock.notifyAll();
return returnValue;
}
}
}
为了进行比较,基于Semaphore
或Condition
对象实现此类队列可能更为自然。这是一个使用一对信号量来表示空/满状态的实现。
public final class SingleBlockingQueue<T> {
private volatile T value;
private final Semaphore full = new Semaphore(0);
private final Semaphore empty = new Semaphore(1);
public void offer(T value) throws InterruptedException {
empty.acquire();
this.value = value;
full.release();
}
public T take() throws InterruptedException {
full.acquire();
T returnValue = value;
value = null; // Should release reference
empty.release();
return returnValue;
}
}
答案 2 :(得分:0)
请注意,由于RxJava-JDBC框架中ResultSet
调用的时间安排,next()
跳过了一些问题。我使用此实现修改先前给出的答案。
public final class SingleBlockingQueue<T> {
private volatile T value;
private final Semaphore nextGate = new Semaphore(0);
private final Semaphore waitGate = new Semaphore(0);
private volatile boolean hasValue = true;
private volatile boolean isFirst = true;
public void offer(T value) throws InterruptedException {
if (isFirst) {
nextGate.acquire();
isFirst = false;
}
this.value = value;
waitGate.release();
nextGate.acquire();
}
public T take() throws InterruptedException {
T returnValue = value;
value = null; // Should release reference
return returnValue;
}
public boolean next() throws InterruptedException {
nextGate.release();
waitGate.acquire();
return hasValue;
}
public void setDone() {
hasValue = false;
waitGate.release();
}
}
我正在使用它:将RxJava Observable<T>
变成Kotlin中的Sequence<T>
。
import com.github.davidmoten.rx.jdbc.QuerySelect
import rx.Observable
import rx.Scheduler
import rx.lang.kotlin.subscribeWith
import java.io.Closeable
class ObservableIterator<T>(
observable: Observable<T>
) : Iterator<T>, Closeable {
private val queue = SingleBlockingQueue<T>()
private val subscription =
observable
.subscribeWith {
onNext { queue.offer(it) }
onCompleted { queue.setDone() }
onError { queue.setDone() }
}
override fun hasNext(): Boolean {
return queue.next()
}
override fun next(): T {
return queue.take()
}
override fun close() {
subscription.unsubscribe()
queue.setDone()
}
}
fun <T> Observable<T>.asSequence() = ObservableIterator(this).asSequence()
fun QuerySelect.Builder.asSequence(scheduler: Scheduler) = get { it }
.subscribeOn(scheduler)
.asSequence()