队列是空的还是民意调查?

时间:2016-01-14 11:20:20

标签: 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");
    }

}

我的问题是我最终会得到&#34; Q是空的!&#34;记录线。 我无法理解它是怎么回事?

isQueueEmpty()表示Q不为空,民意调查表明它是!

你能告诉我吗?

谢谢。

2 个答案:

答案 0 :(得分:1)

假设这个代码是由多个线程访问的,原因是空闲检查和随后的轮询不是原子地完成的:它们是两个独立的动作。这意味着不同的线程可以在第一个线程检查队列之间调用poll,如果它是空的并且调用poll本身;如果只发生队列中的一个元素,其中一个线程将从调用null返回poll

引用Javadoc for Queue

  

队列实现通常不允许插入null元素,尽管某些实现(如LinkedList)不禁止插入null。即使在允许它的实现中,也不应将null插入到Queue中,因为null也被poll方法用作特殊返回值,以指示队列不包含任何元素。

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

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

  • 如果您正在使用像LinkedList这样的非同步实现,那么无论如何,如果多个线程正在修改列表,那么您应该同步它,使poll原子化;
  • BlockingQueue这样的并发实现以原子方式实现poll,因此您无需担心明确地执行任何操作。

TL; DR:

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

答案 1 :(得分:1)

你的队列初始化如下:

m_Queue = new LinkedList<Message>();

LinkedinListQueue的实现,允许 null添加。

基本上您要将null值添加到m_Queue

正如@Andy所提到的,使用poll()方法时不应使用此类实现。

有两种方法可以避免

  1. 在将Message添加到m_Queue之前,您可以检查其null是否
  2. new LinkedList<Message>();new ArrayDequeue<Message>();如果要向队列中添加null,则会抛出异常
  3. 我更喜欢第二个,因为它确实应该是一个队列。