【问题标题】:PriorityBlockingQueue that ensures consecutive item sequencePriorityBlockingQueue 确保连续的项目序列
【发布时间】:2021-06-07 00:00:43
【问题描述】:

我正在接收一系列消息,我想按顺序处理它们。每条消息都有一个序列号。有一个线程池接收它们。我想将它们放入像PriorityBlockingQueue 这样的阻塞队列中,并以正确的顺序读取它们,阻塞直到下一条连续消息可用。

例如给定这段代码:

ConsecutiveBlockingQueue<Integer> q = new ConsecutiveBlockingQueue<>();

new Thread (()->{ q.put(0); q.put(2); }).start();
new Thread (()->{ q.put(1); q.put(3); }).start();

ArrayList<Integer> ordered = new ArrayList<>(4);
for (int i = 0; i < 4; i++) {
    ordered.add(q.take());
}
System.out.println(ordered);

我希望它打印 [0, 1, 2, 3]

【问题讨论】:

  • 是的,PriorityBlockingQueue 就是这样做的。你的问题?
  • @user207421 这不是 PriorityBlockingQueue 所做的。 PriorityBlockingQueue 仅在为空或已满时阻塞。我需要一个队列,该队列在 0 和 1 被占用后也会阻塞,其中有 3 个,但缺少 2 个。如果在我的示例中将 Tread.sleep 添加到 t2,您将看到结果不会是 [0, 1, 2, 3]
  • 据我所知,JDK 中没有任何东西可以满足您的需求。不过那里可能有一个图书馆。然而,当涉及到它时,自己实现它应该不会太难。如果您只想要基本行为,至少不会。你甚至可以在内部使用PriorityQueue

标签: java algorithm concurrency priority-queue java.util.concurrent


【解决方案1】:

这是一个经过最低限度测试的课程,似乎可以满足我的要求。欢迎评论。

package com.ciphercloud.sdp.common;

import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Iterator;
import java.util.PriorityQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.ToIntFunction;

public class ConsecutiveBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E> {
    private final ToIntFunction <E> ixFunction;
    // blocking queue for consecutive items. Take operations will look into this queue
    LinkedBlockingQueue <E> bQueue = new LinkedBlockingQueue<>();

    // buffering/ordering queue for items that are out of sequence
    PriorityQueue <E> pQueue = new PriorityQueue<>();

    ReentrantLock lock = new ReentrantLock();

    private int nextIx;

    ConsecutiveBlockingQueue(ToIntFunction <E> ixFunction) {
        this(0, ixFunction);
    }

    ConsecutiveBlockingQueue(int startIx, ToIntFunction <E> ixFunction) {
        nextIx = startIx;
        this.ixFunction = ixFunction;
    }

    @Override
    public Iterator <E> iterator() {
        return bQueue.iterator();
    }

    @Override
    public int size() {
        return bQueue.size();
    }

    protected BlockingQueue <E> delegate() {
        return bQueue;
    }

    @Override
    public int remainingCapacity() {
        return Integer.MAX_VALUE;
    }

    @Override
    public int drainTo(Collection <? super E> c) {
        return bQueue.drainTo(c);
    }

    @Override
    public int drainTo(Collection <? super E> c, int maxElements) {
        return bQueue.drainTo(c, maxElements);
    }

    @Override
    public void put(E e) {
        offer(e);
    }

    @Override
    public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
        offer(e);
        return true;
    }

    @Override
    public boolean offer(E e) {
        lock.lock();
        try {
            if (ixFunction.applyAsInt(e) == nextIx) {
                // offered item is the next consecutive expected one
                // put it directly into the blocking queue
                bQueue.offer(e);
                nextIx++;

                // if there are any buffered items in the pQueue, move them
                // into the blocking queue while they follow consecutively
                while(true) {
                    E next = pQueue.peek();
                    if(next == null || ixFunction.applyAsInt(next) != nextIx) {
                        // no more items in pQueue, or next item is not consecutive
                        break;
                    }
                    pQueue.poll();
                    bQueue.offer(next);
                    nextIx++;
                }
            } else {
                // offered item is not consecutively next. Buffer it in pQueue
                pQueue.offer(e);
            }
        } finally {
            lock.unlock();
        }

        return true;
    }


    @Override
    public E take() throws InterruptedException {
        return bQueue.take();
    }

    @Override
    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        return bQueue.poll(timeout, unit);
    }


    @Override
    public E poll() {
        return bQueue.poll();
    }

    @Override
    public E peek() {
        return bQueue.peek();
    }
}

【讨论】:

    猜你喜欢
    • 2012-04-02
    • 1970-01-01
    • 2019-09-30
    • 2015-06-30
    • 1970-01-01
    • 2021-07-24
    • 1970-01-01
    • 2021-06-10
    • 2016-07-17
    相关资源
    最近更新 更多