java - Queue isEmpty 和 poll 不一致?

标签 java collections

请参阅以下代码段:

private static Queue<Message> m_Queue;

public boolean isQueueEmpty()
{
    if (m_Queue.isEmpty())
        return true;
    else
        return false;
}


public WgwConferenceMessage dequeue(){
try{
 if(!isQueueEmpty())
 {
    Message message = m_Queue.poll();

    if (message != null)
    {
        if (!message.getMessage().equals(""))
            Log4jWrapper.writeLog("Retrieved "  + message.getMessage() + " from queue");
        else
            Log4jWrapper.writeLog(LogLevelEnum.ERROR, "<Queue> dequeue", "Message empty");

        return message;
    }
    else
    {
        Log4jWrapper.writeLog(LogLevelEnum.TRACE, "<Queue> dequeue", " Q is empty!");
        return null;
    }
 }
 else
    return null;
}
catch (Exception e)
{
    ExceptionHandler.printException(e, "<Queue>", "dequeue");
    return null;
}
}

public void enqueue(Message a_Message) throws Exception
{
    try
    {
        if (m_Queue.offer(a_Message))
            Log4jWrapper.writeLog(LogLevelEnum.TRACE, "<Queue> enqueue", "Pushed "  + a_Message.getMessage() + " to queue");
        else
            throw new Exception("Queue - Could not push message to queue");
    }
    catch (Exception e)
    {
        ExceptionHandler.printException(e, "Queue", "enqueue");
    }

}

我的问题是最终我得到“Q 为空!”日志行。 我不明白怎么会这样?

isQueueEmpty() 表示 Q 不为空,而 poll 则表示为空!

您能给点建议吗?

谢谢。

最佳答案

假设此代码由多个线程访问,原因是空性检查和后续轮询不是以原子方式完成的:它们是两个单独的操作。这意味着不同的线程可以在第一个线程检查队列是否为空和调用 poll 本身之间调用队列上的 poll ;如果队列中恰好只有一个元素,则其中一个线程将从调用 poll 中返回 null

引用Javadoc for Queue :

Queue implementations generally do not allow insertion of null elements, although some implementations, such as LinkedList, do not prohibit insertion of null. Even in the implementations that permit it, null should not be inserted into a Queue, as null is also used as a special return value by the poll method to indicate that the queue contains no elements.

这意味着您应该使用 poll 返回 null 作为队列为空的指示 - 您不需要单独进行调用.

poll 可能是原子的 - 取决于您实际使用的 Queue 的实现:

  • 如果您使用像 LinkedList 这样的非同步实现,并且多个线程正在修改列表,则无论如何都应该同步它,从而使 poll 原子化;<
  • 诸如 BlockingQueue 之类的并发实现以原子方式实现 poll,因此您无需担心显式执行任何操作。

TL;博士:

  • 删除 !isQueueEmpty() 检查
  • 通过选择并发实现或同步队列的突变,确保您的 poll 方法是原子的。

关于java - Queue isEmpty 和 poll 不一致?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34788293/

相关文章:

java - 获取特定的 ArrayList 项

oracle - Plsql 未初始化的集合

java - [Java]数组和集合测试,意外的结果?

c# - 集合下一个元素

vba - 如何在VBA中合并两个集合?

java - 添加具有相同日期的 ArrayList 值

java - 如何使用 Spring 订阅传入的 SSE 事件

java - Java线程中的消息对话

java - osgi启动包NoClassDefFoundError

java - 如何使用Java在Mongodb中插入不重复的数据?