Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在java中实现您自己的阻塞队列_Java_Multithreading_Synchronization_Java.util.concurrent_Blockingqueue - Fatal编程技术网

在java中实现您自己的阻塞队列

在java中实现您自己的阻塞队列,java,multithreading,synchronization,java.util.concurrent,blockingqueue,Java,Multithreading,Synchronization,Java.util.concurrent,Blockingqueue,我知道这个问题以前被问过很多次,也被回答过很多次,但我就是无法从互联网上的例子中找出一个窍门,比如一个 这两种解决方案都在put()方法中检查阻塞队列的数组/队列/链接列表是否为空,以notifyAll等待线程,在get()方法中反之亦然。第二个链接中的A强调了这种情况,并提到没有必要这样做 所以问题是,;对我来说,检查队列是否为空,通知所有等待的线程也有点奇怪。有什么想法吗 提前谢谢。我认为在notifyAll()之前进行额外检查在逻辑上没有坏处 一旦您从队列中放入/获取某些内容,您就可以简单

我知道这个问题以前被问过很多次,也被回答过很多次,但我就是无法从互联网上的例子中找出一个窍门,比如一个

这两种解决方案都在
put()
方法中检查阻塞队列的数组/队列/链接列表是否为空,以
notifyAll
等待线程,在
get()
方法中反之亦然。第二个链接中的A强调了这种情况,并提到没有必要这样做

所以问题是,;对我来说,检查队列是否为空,通知所有等待的线程也有点奇怪。有什么想法吗


提前谢谢。

我认为在
notifyAll()之前进行额外检查在逻辑上没有坏处

一旦您从队列中放入/获取某些内容,您就可以简单地
notifyAll()
。一切都将继续工作,并且您的代码更短。但是,在调用
notifyAll()
之前检查是否有人可能在等待(通过检查是否到达队列边界)也没有坏处。这一额外的逻辑节省了不必要的
notifyAll()
调用


这取决于您希望代码更短、更干净,或者希望代码运行更高效。(没有研究过notifyAll()
的实现。如果没有人等待,那么这是一个廉价的操作,那么额外检查的性能增益可能并不明显)

作者使用
notifyAll()
的原因很简单:他们不知道这是否必要,所以他们决定“更安全”选择权

在上面的示例中,只需调用
notify()
就足够了。对于添加的每个元素,在所有情况下都只能提供一个线程等待

如果您的队列也可以选择在一个步骤中添加多个元素,如
addAll(Collection list)
,那么这一点就变得更加明显了,因为在这种情况下,可以为多个等待空列表的线程提供服务,确切地说:添加的线程数与添加的元素数相同

然而,在特殊的单元素情况下,
notifyAll()
会导致额外的开销,因为许多线程被不必要地唤醒,因此必须再次进入睡眠状态,同时阻塞队列访问。因此,在这种特殊情况下,将
notifyAll()
替换为
notify()
将提高速度


但是根本不使用wait/notify和synchronized,而是使用并发包将比任何智能wait/notify实现都能提高速度。

我知道这是一个老问题,但在阅读了问题和答案后,我忍不住要问自己,我希望你觉得这有用

关于在通知其他等待的线程之前检查队列是否已满或为空,您缺少了一些方法,这两种方法都是
put(T)
T get(),但这不会阻止它们一起工作,因此如果一个线程a已经输入了
put(T)
方法,另一个线程b仍然可以在线程a退出
put(T)
之前输入并开始执行
T get()
方法中的指令,因此,这种
双重检查
设计将使开发人员感到更安全一点,因为您不知道将来是否会或何时会发生cpu上下文切换

更好、更推荐的方法是使用
可重入锁
条件

//我已经编辑了这篇文章的源代码

使用这种方法不需要重复检查,因为两个方法之间共享了锁定对象,这意味着一次只能有一个线程a或b进入这些方法中的任何一个,这与创建不同监视器的同步方法不同,只有那些因为队列已满而等待的线程在有更多空间时才会收到通知,而等待的线程也是如此,因为队列为空,这将提高cpu利用率。
您可以通过源代码找到更详细的示例

我想编写一个简单的阻塞队列实现,它将帮助人们轻松理解这一点。这是为新手准备的

class BlockingQueue {
private List queue = new LinkedList();

private int limit = 10;

public BlockingQueue(int limit){
    this.limit = limit;
}

public synchronized void enqueue(Object ele) throws InterruptedException {
    while(queue.size() == limit)
        wait();
    if(queue.size() == 0)
        notifyAll();
    // add
    queue.add(ele);
}

public synchronized Object deque() throws InterruptedException {
    while (queue.size() == 0)
        wait();
    if(queue.size() == limit)
        notifyAll();
    return queue.remove(0);
}
}



部分问题涉及在并发程序中正确使用
等待
通知
的困难;引用Joshua Bloch的话,它们就像“并发编程的低级(汇编语言)”。他提倡使用
notifyAll
,等待线程在收到通知时应始终在循环中进行检查,以便它们可以根据需要继续等待。实际上,您根本不应该使用wait/notify,而是始终计划使用JavaSE5中提供的更高级别并发API。不是线程和等待/通知,而是从任务和执行者的角度设计并发应用。是的,我完全同意你的观点,老一套但好一点:没有必要重新发明轮子。但是想想看,我们需要在这个案例中使用wait和notifyAll。我知道wait()应该在循环中使用,所有这些都在javadocs(虚假唤醒)中解释过。但是黑客们对通知的条件有什么看法呢?这是我无法理解的要点。请看-他们使用了
ReentrantLock
条件
s,而不是
等待
/
通知
。我们正在脱离问题的范围!我确实在寻找实际的实现,但对于自实现的阻塞队列来说,这可能是最简单的方法,为什么在不同的解决方案中存在相同的“如果”条件?只是复制粘贴?无意识编码?:)我正在阅读jenkov的教程,据我所知,在
deque
中添加了
if(this.queue.size()==this.limit){notifyAll();}
,因为
class BlockingQueue {
private List queue = new LinkedList();

private int limit = 10;

public BlockingQueue(int limit){
    this.limit = limit;
}

public synchronized void enqueue(Object ele) throws InterruptedException {
    while(queue.size() == limit)
        wait();
    if(queue.size() == 0)
        notifyAll();
    // add
    queue.add(ele);
}

public synchronized Object deque() throws InterruptedException {
    while (queue.size() == 0)
        wait();
    if(queue.size() == limit)
        notifyAll();
    return queue.remove(0);
}