阻塞队列元素对其他线程不可见,有时会导致无法检索任何元素

Blocking Queue elements are not visible to other thread sometimes causing no elements to retrieve

提问人:Siva Ram 提问时间:7/18/2019 最后编辑:Siva Ram 更新时间:7/19/2019 访问量:277

问:

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

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

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

问题是在我的环境的 1 中,有时第二个线程是空的,尽管我可以看到第一个线程在放置时阻塞调用(因为我已将队列大小初始化为 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 多线程 队列 阻塞

评论


答:

0赞 John Vint 7/18/2019 #1

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

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

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

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

公共 E take()

检索并删除此队列的头部,并在必要时等待,直到元素可用。

然后,您在此处的用法将是:

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

评论

0赞 Siva Ram 7/19/2019
嗨,jhon感谢您的回复,我明白了你的意思,但我的疑问是在这种情况下,因为队列是线程安全的,每当另一个线程将元素放入Q时,它总是会看到,大小将大于0,因此它将从Q中删除。这是我所期待的,但不是这样发生的,这是我无法理解的
0赞 John Vint 7/19/2019
首先,永远不要调用该方法。首次调用时,队列很可能是空的,但线程将挂起,直到另一个线程 s。正在进行线程通信(推杆线程唤醒正在接收的线程)。sizetake()put()
0赞 Siva Ram 7/24/2019
但是根据 java 文档,size 将返回 Q 中的元素,所以它没有任何问题,对吧?
0赞 John Vint 7/24/2019
BlockingQueue 的目的是让线程等待队列具有元素。大多数情况下,队列将是空的。 没问题。如果你想等待/阻止一个元素存在,你不必担心队列的大小。根据您的示例,您似乎应该等待一个元素出现在队列中so its not having any issue right?
0赞 Siva Ram 7/25/2019
是的,我已经尝试过同样的方法,但原始问题是,从第二个线程有时它无法获取元素,我已经采取了线程转储,并且在第一个线程中将对象放入 Q,但从第二个线程中,它从未检索到线程只是卡在获取条件