我正在尝试使用尾递归函数对SynchronizedQueue进行一些处理。该函数似乎工作正常,但我对并发性的考虑越多,我相信在使用不同的线程访问此队列时,我可能会遇到一些竞争条件。这是我认为我可以使用的功能:
val unsavedMessages = new SynchronizedQueue[CachedMessage]()
val MAX_BATCH = 256
val rowCount = new AtomicInteger()
private def validateCacheSize() = if (unsavedMessages.length > MAX_BATCH) {
implicit val batch = createBatch
val counter = rowCount.getAndIncrement
@tailrec
def processQueue(queue: SynchronizedQueue[CachedMessage]): Unit = if (queue.nonEmpty) {
val cm = queue.dequeue
addToBatch(cm.request, cm.timestamp, cm.brokerId, counter)
processQueue(queue)
}
processQueue(unsavedMessages)
executeBatch
resetQueue
}
def resetQueue = unsavedMessages.clear
多个线程调用此函数:
def add(request: WebserviceRuleMatch, timestamp: Long, brokerId: String) = {
validateCacheSize
//log.info("enquing request "+ unsavedMessages.length)
unsavedMessages.enqueue(CachedMessage(request, timestamp, brokerId))
}
有没有人对如何改善这一点有任何指示,以便可能没有竞争条件?
答案 0 :(得分:1)
从未来调用add函数,所以我觉得队列可能在queue.nonempty和queue.dequeue之间被清空。
是的,它可以。您可以使用双重检查锁定来使validateCacheSize
单线程。 (顺便说一下,这种方法似乎有一个非常误导的名字!)
另外我认为可以通过processQueue和resetQueue之间的线程添加消息。
是的,他们可以。但为什么你需要打电话给unsavedMessages.clear
? queue.dequeue
已将其从队列中删除。因此,队列中应该存在的唯一unsavedMessages
是仍然需要处理的。{/ p>
答案 1 :(得分:1)
队列有可能在queue.nonempty和queue.dequeue之间清空队列
避免调用必须在代码中同步的多个队列操作。使用SynchronizedQueue
的强大功能进行原子线程安全操作。例如。避免完全调用queue.nonempty
(替代尾递归):
for (cm <- unsavedMessages.dequeueAll(_ => true))
addToBatch(cm.request, cm.timestamp, cm.brokerId, counter)
executeBatch
//resetQueue -- Don't do this! Not thread-safe
我认为可以通过processQueue和resetQueue
之间的线程添加消息
罗宾格林:(顺便说一句,这种方法似乎有一个非常误导的名字!)