Java高效的调度结构?
我为这个问题的长度表示歉意,但考虑到我正在寻找解决问题的合适方法,而不是简单的代码建议,我认为包含足够的细节是很重要的Java高效的调度结构?,java,algorithm,scheduling,Java,Algorithm,Scheduling,我为这个问题的长度表示歉意,但考虑到我正在寻找解决问题的合适方法,而不是简单的代码建议,我认为包含足够的细节是很重要的 一般说明: 我正在从事一个项目,该项目要求能够以相对重复的时间间隔“安排”任务 这些间隔是以一些内部时间表示的,这些时间表示为一个整数,随着程序的执行而递增(因此不等于实时)。每次发生这种情况时,将对计划进行互选,以检查在此时间步执行的任何任务 如果执行了任务,则应重新安排该任务在相对于当前时间的位置再次运行(例如,在5个时间步内)。此相对位置仅存储为任务对象的整数属性 问题
一般说明: 我正在从事一个项目,该项目要求能够以相对重复的时间间隔“安排”任务 这些间隔是以一些内部时间表示的,这些时间表示为一个整数,随着程序的执行而递增(因此不等于实时)。每次发生这种情况时,将对计划进行互选,以检查在此时间步执行的任何任务 如果执行了任务,则应重新安排该任务在相对于当前时间的位置再次运行(例如,在5个时间步内)。此相对位置仅存储为任务对象的整数属性 问题是: 我正在努力决定我应该如何构造它——部分原因是它是一组稍微难以查找的搜索词 目前,我认为每次定时器增加时,我需要:
- 间隔必须是相对的,而不是特定的时间,并且定义为距当前时间的整数步数
- 这些间隔可以采用任何整数值,例如,没有边界
- 可以为同一时间步安排多个任务,但它们的执行顺序并不重要
- 所有执行都应保持在单线程中-由于其他限制,多线程解决方案不适合
非常感谢任何可能的帮助。如有必要,请随时发表评论以获取更多信息,我将根据需要进行编辑 循环链表可能就是您要查找的数据结构。您只需增加循环任务列表中“当前”字段的索引,而不是减少每个任务元素中的字段。伪代码结构可能如下所示:
tick():
current = current.next()
for task : current.tasklist():
task.execute()
任何时候你安排一个新任务,你只需将它添加到当前“勾号”前面的N个勾号位置。好吧,Quartz是非常强大的工具,但是它的配置可能性有限,所以如果你需要特定的功能,你应该编写自己的解决方案 但是,研究Quartz源代码和数据结构是一个好主意,因为它们成功地解决了许多问题,例如数据库级别的进程间同步、运行延迟任务等
我曾经写过一次我自己的调度程序,它适用于propably Quartz不容易适应的任务,但一旦我学习了Quartz,我就明白了我可以在解决方案中改进多少,知道它是如何在Quartz中完成的。这个怎么样,它使用您自己的标记和ExecuteInterval() 使用一个。它拥有你所需要的一切。下面是使用它的简单程度:
// Create a single-threaded ScheduledExecutorService
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); // 1 thread
// Schedule something to run in 10 seconds time
scheduler.schedule(new Runnable() {
public void run() {
// Do something
}}, 10, TimeUnit.SECONDS);
// Schedule something to run in 2 hours time
scheduler.schedule(new Runnable() {
public void run() {
// Do something else
}}, 2, TimeUnit.HOURS);
// etc as you need
以下是一些想法: 保持一切简单。如果您没有数以百万计的任务,那么就不需要优化数据结构(除了自豪感或过早优化的冲动) 避免相对时间。使用绝对内部刻度。如果添加任务,请将“下次运行”设置为当前刻度值。将其添加到列表中,按时间对列表进行排序
寻找任务时,从列表的最前面开始,挑选所有有时间的任务看看
DelayQueue
使用PriorityQueue
来维护这样一个有序的事件列表的方式DelayQueue
使用实时工作,因此可以使用条件
和锁支持
中提供的可变定时等待方法。您可以实现类似于SyntheticDelayQueue
的东西,其行为方式与DelayQueue
相同,但使用您自己的合成时间服务。显然,您必须用jdk替换免费提供的定时等待/信令机制,而这可能是非常重要的,因为要有效地做到这一点。如果必须这样做,我会创建一个简单的队列(链表变体)。此队列将包含一个动态数据结构(例如简单列表),其中包含需要完成的所有任务。在每个时间间隔(或时间步),进程读取队列的第一个节点,执行它在该节点列表中找到的指令。在每次执行结束时,它将计算重新调度,并将新的执行添加到队列中的另一个节点,或者在将指令存储到该节点之前创建到达该位置的节点。然后移除第一个节点,并在下一时间步执行第二个节点(现在是第一个)。该系统也不需要跟踪任何整数,所需的所有数据结构都可以在java语言中找到。这应该可以解决您的问题。在我看来,您希望通过计数器在应用程序中模拟时间。我想知道您为什么不想使用系统时间,即实时?当然,您可以使用quartz实现这一点。您以前使用过quartz吗。@user384706-我正在模拟现场工作
import junit.framework.Assert;
import org.junit.Test;
public class TestScheduler {
private static class Task implements Runnable {
public boolean didRun = false;
public void run() {
didRun = true;
}
}
Runnable fail = new Runnable() {
@Override
public void run() {
Assert.fail();
}
};
@Test
public void queue() {
Scheduler scheduler = new Scheduler();
Task task = new Task();
scheduler.addTask(task, 0);
scheduler.addTask(fail, 1);
Assert.assertFalse(task.didRun);
scheduler.executeNextInterval();
Assert.assertTrue(task.didRun);
}
@Test
public void queueWithGaps() {
Scheduler scheduler = new Scheduler();
scheduler.addTask(fail, 1);
scheduler.executeNextInterval();
}
@Test
public void queueLonger() {
Scheduler scheduler = new Scheduler();
Task task0 = new Task();
scheduler.addTask(task0, 1);
Task task1 = new Task();
scheduler.addTask(task1, 1);
scheduler.addTask(fail, 2);
scheduler.executeNextInterval();
scheduler.executeNextInterval();
Assert.assertTrue(task0.didRun);
Assert.assertTrue(task1.didRun);
}
}
// Create a single-threaded ScheduledExecutorService
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); // 1 thread
// Schedule something to run in 10 seconds time
scheduler.schedule(new Runnable() {
public void run() {
// Do something
}}, 10, TimeUnit.SECONDS);
// Schedule something to run in 2 hours time
scheduler.schedule(new Runnable() {
public void run() {
// Do something else
}}, 2, TimeUnit.HOURS);
// etc as you need