多线程java应用中的数据缓冲

多线程java应用中的数据缓冲,java,java.util.concurrent,Java,Java.util.concurrent,我有一个多线程应用程序,它有一个生产者线程和几个消费者线程。 数据存储在共享的线程安全集合中,并在缓冲区中有足够数据时刷新到数据库 从javadocs- BlockingQueue<E> 检索并删除此队列的头,如有必要,等待元素可用 我的问题- 是否还有另一个集合具有E[]take(int n)方法?i、 阻塞队列等待元素可用。我想要的是 它应该等到100或200个元素可用 或者,是否有另一种方法可以在不进行轮询的情况下解决问题 我不确定在标准库中是否有类似的类具有take(int

我有一个多线程应用程序,它有一个生产者线程和几个消费者线程。 数据存储在共享的线程安全集合中,并在缓冲区中有足够数据时刷新到数据库

从javadocs-

BlockingQueue<E>
检索并删除此队列的头,如有必要,等待元素可用

我的问题-

  • 是否还有另一个集合具有E[]take(int n)方法?i、 阻塞队列等待元素可用。我想要的是 它应该等到100或200个元素可用
  • 或者,是否有另一种方法可以在不进行轮询的情况下解决问题

  • 我不确定在标准库中是否有类似的类具有
    take(int n)
    type方法,但是您应该能够包装默认的
    BlockingQueue
    来添加该函数,而不会有太多麻烦,您认为呢


    另一种情况是触发一个操作,在该操作中,您将元素放入集合中,您设置的阈值将触发刷新。

    drainTo方法并不完全是您想要的,但它是否符合您的目的

    ,int)

    编辑

    您可以使用
    take
    drainTo
    的组合来实现性能稍高的批处理阻塞takemin:

    public <E> void drainTo(final BlockingQueue<E> queue, final List<E> list, final int min) throws InterruptedException
    {
      int drained = 0;
      do 
      {
        if (queue.size() > 0)
          drained += queue.drainTo(list, min - drained);
        else
        {
          list.add(queue.take());
          drained++;
        }
      }
      while (drained < min);
    }
    
    public void drainTo(final BlockingQueue queue,final List List,final int min)抛出中断异常
    {
    int=0;
    做
    {
    if(queue.size()>0)
    排水+=队列.drainTo(列表,最小排水量);
    其他的
    {
    list.add(queue.take());
    抽干++;
    }
    }
    同时(排水
    我认为唯一的方法是扩展
    阻塞队列的一些实现,或者使用
    take
    创建某种实用方法:

    public <E> void take(BlockingQueue<E> queue, List<E> to, int max) 
            throws InterruptedException {
    
        for (int i = 0; i < max; i++)
            to.add(queue.take());
    }
    
    public void take(阻塞队列队列、列表到、int max)
    抛出中断异常{
    对于(int i=0;i
    所以这应该是一个线程安全队列,允许您阻止获取任意数量的元素。欢迎更多的人来验证线程代码是否正确

    package mybq;
    
    import java.util.ArrayList;
    import java.util.LinkedList;
    import java.util.List;
    
    public class ChunkyBlockingQueue<T> {
        protected final LinkedList<T> q = new LinkedList<T>();
        protected final Object lock = new Object();
    
        public void add(T t) {
            synchronized (lock) {
                q.add(t);
                lock.notifyAll();
            }
        }
    
        public List<T> take(int numElements) {
            synchronized (lock) {
                while (q.size() < numElements) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
                ArrayList<T> l = new ArrayList<T>(numElements);
                l.addAll(q.subList(0, numElements));
                q.subList(0, numElements).clear();
                return l;
            }
        }
    }
    
    包mybq;
    导入java.util.ArrayList;
    导入java.util.LinkedList;
    导入java.util.List;
    公共类ChunkyBlockingQueue{
    受保护的最终LinkedList q=新LinkedList();
    受保护的最终对象锁=新对象();
    公共无效添加(T){
    已同步(锁定){
    q、 加(t);
    lock.notifyAll();
    }
    }
    公共列表获取(整数){
    已同步(锁定){
    while(q.size()
    正如另一个答案(现在显然已被删除)中提到的,这正是他/她想要做的。我已经更新了答案,表明它不能解决确切的问题。有时候OP不知道其他的解决方案,所以它总是值得一问。我不敢说这会稍微快一点。。。您多次获取和释放底层的
    (使用drainTo和take方法检查大小)。此外,此实现将依赖于
    drainTo
    方法未使用一系列
    take
    s实现。。。您不能保证:)@dacwe,如果存在单个元素,则任何“合理”的drainTo实现应与
    take
    执行相同,如果存在多个元素,则执行更好。这将是一个奇怪的实现,因为情况并非如此。此外,根据你的相同论点,不能保证对任何方法的调用都会被锁定(可能会使用其他同步方法)。是的,你是正确的,但我的评论是,如果使用一系列的
    take
    s来实现,那么还需要进行需要某种锁定的大小检查。然而,在每天的使用中,它会更快(无论如何都比使用
    take
    快)。在一些奇怪的情况下,我不知道……事实上,你的方法比我的方法更明智,假设只有一个消费者。这种方法根本不能很好地处理InterruptedException,因为如果中断,你会丢失任何元素。如果它不打算处理中断本身,它确实需要向传入的集合中添加元素,或者如果它想捕获并返回到目前为止已耗尽的元素。元素是否应平均分配给每个使用者,或者take方法的第一个使用者是否应获得第一个
    n
    元素,第二个消费者是下一个
    n
    元素,等等?这真的是你想要做的吗?如果生产速度慢到超出您最终调整的范围,那么在生成数据和将数据刷新到数据库之间会引入几乎任意大的延迟。如果您真的需要进行缓冲,那么您的逻辑应该更像是“等待,直到我有N个元素或X ms已通过”,为什么要等待?为什么不直接使用
    drain()
    ?我会将所有可用数据写入到某个最大值,我更希望不会丢失数据。@SimonC所有消费者都应该获得相同的数据集。应删除已交付给所有人的数据。这就是为什么到目前为止,所提出的解决方案中没有一个对我有帮助。不管怎么说,通过他们还可以收集到很多知识。:-)@DRMacIver的生产率不是问题。它是一种固定速率为.5秒的化学传感器
    notifyAll
    in
    
    
    package mybq;
    
    import java.util.ArrayList;
    import java.util.LinkedList;
    import java.util.List;
    
    public class ChunkyBlockingQueue<T> {
        protected final LinkedList<T> q = new LinkedList<T>();
        protected final Object lock = new Object();
    
        public void add(T t) {
            synchronized (lock) {
                q.add(t);
                lock.notifyAll();
            }
        }
    
        public List<T> take(int numElements) {
            synchronized (lock) {
                while (q.size() < numElements) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
                ArrayList<T> l = new ArrayList<T>(numElements);
                l.addAll(q.subList(0, numElements));
                q.subList(0, numElements).clear();
                return l;
            }
        }
    }