我有以下情况:
线程A将向线程B和C发送许多任务(确切的任务数量未知)
对于每个任务,线程A将同时(异步)将其发送到B和C,然后如果B或C中的任何一个成功完成任务或两者都失败,A将继续发送下一个任务。这里的想法是尽可能避免阻塞。即,对于相同的任务,当B在C仍在处理时完成它时,A可以立即发送下一个任务,而不需要等待C来获得结果。
只要任务由另一个完成,预计B和C中较慢的一个可以跳过某些任务。例如,B可以完成任务t1 t2 t3 t4,并且C仅完成t1 t4,因为当C接收到t2和t3时,由于某种原因它仍在处理t1。
是否有适合此的线程同步构造?我正在检查java.util.concurrent.Phaser
,但似乎不符合我的需要。欢迎提出任何意见,谢谢。
答案 0 :(得分:2)
如果使用Future
或者actor而不是Threads作为构建块,这会更容易。直接在线程上执行此操作可能会导致许多问题,因为您必须处理详细信息,例如排队传入的消息。另一个问题是,如果你想要解决的问题反映了你所要求的内容,那么我无法理解 - 执行同一任务两次的价值,2不同的线程?那只是感觉不对。
这是一个天真的非阻塞实现,可以了解所涉及的内容,但不要在实际代码中执行此操作(确实考虑更高级别的抽象):
val queue = new AtomicReference(Queue.empty[Runnable])
def worker() = new Thread(new Runnable {
@tailrec
def run() = {
val currentQueue = queue.get
if (currentQueue.nonEmpty) {
val (task, updatedQueue) = currentQueue.dequeue
try {
task.run()
} catch {
case NonFatal(ex) =>
ex.printStackTrace()
}
// if this fails, then another worker succeeded
queue.compareAndSet(currentQueue, updatedQueue)
// process next task in queue
if (updatedQueue.nonEmpty) run()
}
}
})
@tailrec
def submitTask(task: Runnable): Unit = {
val currentQueue = queue.get
val newQueue = currentQueue.enqueue(task)
if (!queue.compareAndSet(currentQueue, newQueue))
submitTask(task)
else if (currentQueue.isEmpty) {
// because of the CAS above, only 2 workers will be
// active at the same time
worker().start()
worker().start()
}
}
答案 1 :(得分:1)
我会在Balancing Workloads Across Nodes with Akka 2上使用变体,除了不为每个工作人员分配一个工作项,它会将当前工作项分配给请求工作的每个工作人员,直到工作项完成。
看起来有点矫枉过正,但这种模式可以很好地扩展,并且易于定制。我使用它在Production中有两个项目,有others。这种方法是一种“拉动”#34;方法
A"推动"使用演员的方法需要工人演员that only process the last message in their mailbox。然后,主要参与者将所有消息转发给所有工作者。
答案 2 :(得分:0)
考虑使用一些Executor
,例如Executors.newFixedThreadPool()
。它允许:
Future
接口,让您检查任务是否成功完成,仍在进行中或失败; Future.get()
方法阻塞直到任务完成/未能完成的事实来实现; 我认为这些功能涵盖了您编写的行为要求。