我有一个ArrayBlocking队列,单个线程固定速率Scheduled工作。 我的任务可能失败了。我想重新运行或重新插入高优先级或顶级的队列
答案 0 :(得分:1)
这里有些想法 -
你为什么使用ArrayBlockingQueue而不是PriorityBlockingQueue?听起来像你需要我。首先将所有元素设置为具有相同的优先级。
如果您收到异常 - 重新插入具有更高优先级的队列
答案 1 :(得分:0)
最简单的事情可能是优先级队列。将重试编号附加到任务。它从零开始。运行不成功后,丢弃所有的并增加零并以高优先级将它们放回队列中。使用此方法,如果您以后想要,可以轻松决定运行三次或更多次。缺点是您必须修改任务类。
另一个想法是建立另一个非阻塞,线程安全的高优先级队列。在查找新任务时,首先检查非阻塞队列并运行其中的内容。否则,请转到阻止队列。这可能对你有用,到目前为止它是最简单的解决方案。问题是当阻塞队列阻塞调度程序时,高优先级队列可能会填满。
要解决这个问题,你必须自己做阻止。两个队列都应该是非阻塞的。 (建议:java.util.concurrent.ConcurrentLinkedQueue。)在监视器上轮询两个没有结果的队列后wait()
。当任何东西放入队列时,它应该调用notifyAll()
并且调度程序可以再次启动。在调度程序检查了两个队列之后但在调用wait()
之前,需要非常小心,以免发生通知。
<强>增加:强>
具有手动阻止的第三种解决方案的原型代码。建议使用一些线程,但读者最了解自己的情况。哪些代码容易阻塞等待锁定,这些代码在执行大量工作时容易将其线程(和核心)占用几分钟,并且无法忍受等待其他代码完成所有需要考虑。例如,如果失败的运行可以立即在同一个线程上重新运行而没有耗时的清理,那么大部分代码都可以被废弃。
private final ConcurrentLinkedQueue mainQueue = new ConcurrentLinkedQueue();
private final ConcurrentLinkedQueue prioQueue = new ConcurrentLinkedQueue();
private final Object entryWatch = new Object();
/** Adds a new job to the queue. */
public void addjob( Runnable runjob ) {
synchronized (entryWatch) { entryWatch.notifyAll(); }
}
/** The endless loop that does the work. */
public void schedule() {
for (;;) {
Runnable run = getOne(); // Avoids lock if successful.
if (run == null) {
// Both queues are empty.
synchronized (entryWatch) {
// Need to check again. Someone might have added and notifiedAll
// since last check. From this point until, wait, we can be sure
// entryWatch is not notified.
run = getOne();
if (run == null) {
// Both queues are REALLY empty.
try { entryWatch.wait(); }
catch (InterruptedException ie) {}
}
}
}
runit( run );
}
}
/** Helper method for the endless loop. */
private Runnable getOne() {
Runnable run = (Runnable) prioQueue.poll();
if (run != null) return run;
return (Runnable) mainQueue.poll();
}
/** Runs a new job. */
public void runit( final Runnable runjob ) {
// Do everthing in another thread. (Optional)
new Thread() {
@Override public void run() {
// Run run. (Possibly in own thread?)
// (Perhaps best in thread from a thread pool.)
runjob.run();
// Handle failure (runit only, NOT in runitLast).
// Defining "failure" left as exercise for reader.
if (failure) {
// Put code here to handle failure.
// Put back in queue.
prioQueue.add( runjob );
synchronized (entryWatch) { entryWatch.notifyAll(); }
}
}
}.start();
}
/** Reruns a job. */
public void runitLast( final Runnable runjob ) {
// Same code as "runit", but don't put "runjob" in "prioQueue" on failure.
}