没有同步的Java等待/通知实现

时间:2018-02-15 09:38:50

标签: java locking wait semaphore notify

我有几十个生产者和一个单一消费者的情景。时机至关重要:出于性能原因,我想避免任何生产者锁定,我希望消费者在没有消息准备好的情况下尽可能少地等待。

我已经开始使用ConcurrentLinkedQueue了,但是我不想在sleep时给消费者打电话queue.poll() == null,因为我可能会浪费宝贵的毫秒数,而且我不会这样做。我想使用yield,因为我最终浪费了cpu。

所以我开始实现一种ConcurrentBlockingQueue,以便消费者可以运行类似的东西:

T item = queue.poll();
if(item == null) {
    wait();
    item = queue.poll();
}
return item;

和制片人一样:

queue.offer(item);
notify();

不幸的是,wait / notify仅适用于synchronized块,这反过来会大大降低生产者的性能。 是否还有其他不需要同步的等待/通知机制实现?

我知道没有等待和通知已同步的风险,我设法通过运行以下内容的外部线程解决它们:

while(true) {
    notify();
    sleep(100);
}

2 个答案:

答案 0 :(得分:3)

  

我已开始使用ConcurrentLinkedQueue,但在queue.poll() == null

时,我不想给消费者打电话。

您应该检查the BlockingQueue interface,其中take方法会阻止,直到某个项目可用为止。

它有几个实现,详见javadoc,但ConcurrentLinkedQueue不是其中之一:

  

所有已知的实施课程:
  ArrayBlockingQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, LinkedTransferQueue, PriorityBlockingQueue, SynchronousQueue

答案 1 :(得分:0)

我推出了以下实现:

private final ConcurrentLinkedQueue<T> queue = new ConcurrentLinkedQueue<>();
private final Semaphore semaphore = new Semaphore(0);
private int size;

public void offer(T item) {
    size += 1;
    queue.offer(item);
    semaphore.release();
}

public T poll(long timeout, TimeUnit unit) {
    semaphore.drainPermits();
    T item = queue.poll();
    if (item == null) {
        try {
            semaphore.tryAcquire(timeout, unit);
        } catch (InterruptedException ex) {
        }
        item = queue.poll();
    }
    if (item == null) {
        size = 0;
    } else {
        size = Math.max(0, size - 1);
    }
    return item;
}

/** An inaccurate representation O(1)-access of queue size. */
public int size() {
    return size;
}

具有以下属性:

  • 生产者永远不会进入SLEEP状态(我认为可以使用BlockingQueue中使用Lock的{​​{1}}实现,或使用wait / notify的同步块实现
  • 当队列为空时,消费者只会进入SLEEP状态,但只要生产者提供了一个项目(没有固定时间offer(),没有sleep
  • ,它很快就会被唤醒
  • 消费者可能有时甚至被空队列唤醒,但这里可以浪费一些cpu周期

jdk中有没有我不知道的等效实现?开放批评。