在Java中实现自己的阻塞队列 [英] implement-your-own blocking queue in java

查看:320
本文介绍了在Java中实现自己的阻塞队列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道这个问题以前已经被问过很多次,但是我只是想不通互联网上的例子,例如 a>一个.

这两种解决方案都在put()方法中检查阻塞队列的数组/队列/链表是否为notifyAll等待线程,反之亦然.第二个链接中的评论强调了这种情况,并指出这是不必要的.

问题是;检查队列是否为空对我来说似乎也有些奇怪.通知所有正在等待的线程.有什么想法吗?

谢谢.

解决方案

到目前为止,我知道这是一个老问题,但是在阅读了该问题和答案后,我无济于事,希望您觉得这个有用. /p>

关于在通知其他等待线程之前检查队列是否实际上已满或为空,您遗漏了一些方法,这两种方法put (T t)T get()都是synchronized方法,这意味着只有一个线程可以输入一个一次只能使用这些方法,但这不会阻止它们一起工作,因此,如果线程a已进入put (T t)方法,另一个线程b仍可以在线程a之前进入并开始执行T get()方法中的指令已经退出put (T t),因此这种double-checking设计将使开发人员感到更加安全,因为您不知道将来的cpu上下文切换是否会或何时会发生.

一种更好且更推荐的方法是使用Reentrant LocksConditions:

///我已经从此链接

编辑了源代码

Condition isFullCondition;
Condition isEmptyCondition;
Lock lock;

public BQueue() {
    this(Integer.MAX_VALUE);
}

public BQueue(int limit) {
    this.limit = limit;
    lock = new ReentrantLock();
    isFullCondition = lock.newCondition();
    isEmptyCondition = lock.newCondition();
}

public void put (T t) {
    lock.lock();
    try {
       while (isFull()) {
            try {
                isFullCondition.await();
            } catch (InterruptedException ex) {}
        }
        q.add(t);
        isEmptyCondition.signalAll();
    } finally {
        lock.unlock();
    }
 }

public T get() {
    T t = null;
    lock.lock();
    try {
        while (isEmpty()) {
            try {
                isEmptyCondition.await();
            } catch (InterruptedException ex) {}
        }
        t = q.poll();
        isFullCondition.signalAll();
    } finally { 
        lock.unlock();
    }
    return t;
}

使用这种方法,不需要double checking,因为lock对象在两种方法之间共享,这意味着一次线程a或b一次可以进入这些方法中的任何一种,这与同步方法不同,后者会创建不同的监视器,只有有更多空间时才会通知那些由于队列已满而正在等待的线程,而由于队列为空而等待的线程也将得到通知,这将导致更好的cpu利用率. 您可以找到包含源代码这里

I know this question has been asked and answered many times before, but I just couldn't figure out a trick on the examples found around internet, like this or that one.

Both of these solutions check for emptiness of the blocking queue's array/queue/linkedlist to notifyAll waiting threads in put() method and vice versa in get() methods. A comment in the second link emphasizes this situation and mentions that that's not necessary.

So the question is; It also seems a bit odd to me to check whether the queue is empty | full to notify all waiting threads. Any ideas?

Thanks in advance.

解决方案

I know this is an old question by now, but after reading the question and answers I couldn't help my self, I hope you find this useful.

Regarding checking if the queue is actually full or empty before notifying other waiting threads, you're missing something which is both methods put (T t) and T get() are both synchronized methods, meaning that only one thread can enter one of these methods at a time, yet this will not prevent them from working together, so if a thread-a has entered put (T t) method another thread-b can still enter and start executing the instructions in T get() method before thread-a has exited put (T t), and so this double-checking design is will make the developer feel a little bit more safe because you can't know if future cpu context switching if will or when will happen.

A better and a more recommended approach is to use Reentrant Locks and Conditions:

//I've edited the source code from this link

Condition isFullCondition;
Condition isEmptyCondition;
Lock lock;

public BQueue() {
    this(Integer.MAX_VALUE);
}

public BQueue(int limit) {
    this.limit = limit;
    lock = new ReentrantLock();
    isFullCondition = lock.newCondition();
    isEmptyCondition = lock.newCondition();
}

public void put (T t) {
    lock.lock();
    try {
       while (isFull()) {
            try {
                isFullCondition.await();
            } catch (InterruptedException ex) {}
        }
        q.add(t);
        isEmptyCondition.signalAll();
    } finally {
        lock.unlock();
    }
 }

public T get() {
    T t = null;
    lock.lock();
    try {
        while (isEmpty()) {
            try {
                isEmptyCondition.await();
            } catch (InterruptedException ex) {}
        }
        t = q.poll();
        isFullCondition.signalAll();
    } finally { 
        lock.unlock();
    }
    return t;
}

Using this approach there's no need for double checking, because the lock object is shared between the two methods, meaning only one thread a or b can enter any of these methods at a time unlike synchronized methods which creates different monitors, and only those threads waiting because the queue is full will be notified when there's more space, and the same goes for threads waiting because the queue is empty, this will lead to a better cpu utilization. you can find more detailed example with source code here

这篇关于在Java中实现自己的阻塞队列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆