【问题标题】:Blocking Queue elements are not visible to other thread sometimes causing no elements to retrieve阻塞队列元素对其他线程不可见有时会导致没有元素检索
【发布时间】:2019-07-18 10:58:28
【问题描述】:

我正在使用LinkedBlokingQueue,它在 2 个线程之间共享。从第一个线程构造函数我已将Queue 对象传递给第二个线程。

我在第一个线程中使用likedBlockingQueue.put

第二个线程使用likedBlockingQueue.size()>0likedBlockingQueue.peek() 获取元素。

问题出在我的环境中,有时第二个线程为空,尽管我可以看到第一个线程在 put 处处于阻塞调用(因为我已将队列大小初始化为 1)。这个问题并不总是发生,但有时只会复制。根据 java 文档,无法理解导致此问题的原因,此队列似乎是线程安全的。有人可以就此分享任何观点吗?

我尝试复制这个,但只发生了几次,其他时候我可以从队列中获取元素。

1 个主题

private final Queue<T> linkedQ = new LinkedBlokingQueue(1);
linkedQ.put(element);

2 线程

while(condition)
{
    if(this.linkedQ.size>0)
    {
        Object a = this.linkedQ.peek();
        linkedQ.remove();
        break;
    }
}

没有错误,出现这个问题的时候调试,第二个线程中的Q显示为空。

【问题讨论】:

    标签: java multithreading queue blocking


    【解决方案1】:

    在这种情况下,您不应使用size()peek()remove()LinkedBlockingQueue 是一个阻塞队列(因此​​得名)。 size()peek() 都是非阻塞的(好吧,从技术上讲,它们会阻塞一秒钟,但它们不会以生产者-消费者的方式行事)。

    您需要一个告诉当前线程“在此等待,直到元素出现在队列中”的操作。查看 API,peek() 显示为

    检索但不删除此队列的头部,如果此队列为空,则返回 null。

    如果队列为空,则返回 null 说明不执行等待。您要查找的操作是take()

    public E take()

    检索并移除此队列的头部,如有必要,等待元素可用。

    你在这里的用法是:

    while(condition) {
        Object a = linkedQ.take(); // leaving out the interrupted exception for brevities sake
    }
    

    【讨论】:

    • 您好 jhon 感谢您的回复,我明白了您的意思,但我怀疑在这种情况下,因为队列是线程安全的,每当其他线程将元素放入 Q 时,它总是会看到,将获得大小大于 0,所以它会从 Q 中删除。这是我所期待的,但不是这样发生的,这就是我无法理解的
    • 首先,您永远不应该调用size 方法。在第一次调用take() 时,队列很可能是空的,但是线程会挂起直到另一个线程put()s。正在进行线程通信(放入线程唤醒取出线程)。
    • 但是根据java doc,size会返回Q中的元素,所以没有任何问题吧?
    • BlockingQueue 的目的是让一个线程等待,直到队列有一个元素。大多数时候队列是空的。 so its not having any issue right? 没问题。如果要等待/阻止元素存在,则无需担心队列的大小。根据您的示例,您似乎应该等待一个元素在队列中
    • 是的,我也尝试过,但最初的问题是从第二个线程有时它无法获取元素,我已经进行了线程转储,并且在第一个线程中将对象放入 Q 但从第二个线程它从未检索到线程只是卡在采取条件
    猜你喜欢
    • 1970-01-01
    • 2012-12-06
    • 1970-01-01
    • 1970-01-01
    • 2017-08-10
    • 2014-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多