请参阅以下代码段:
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不为空,民意调查表明它是!
你能告诉我吗?谢谢。
答案 0 :(得分:1)
假设这个代码是由多个线程访问的,原因是空闲检查和随后的轮询不是原子地完成的:它们是两个独立的动作。这意味着不同的线程可以在第一个线程检查队列之间调用poll
,如果它是空的并且调用poll
本身;如果只发生队列中的一个元素,其中一个线程将从调用null
返回poll
。
队列实现通常不允许插入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>();
LinkedinList
是Queue
的实现,允许 null
添加。
基本上您要将null
值添加到m_Queue
正如@Andy所提到的,使用poll()
方法时不应使用此类实现。
有两种方法可以避免
Message
添加到m_Queue
之前,您可以检查其null
是否new LinkedList<Message>();
到new ArrayDequeue<Message>();
如果要向队列中添加null,则会抛出异常我更喜欢第二个,因为它确实应该是一个队列。