我正在尝试创建一个ScheduledExecutorService,其中一次只有一个任务处于活动状态,并且只有在一个任务完成后,下一个任务才会以任意延迟量开始延迟。
作为一个非常简单的例子,看看这个方法。这个方法的想法是调度10个Runnable来模拟从10到1的倒计时。每个间隔需要一秒(想象一下这是一个任意的秒数,但是,我不能在我的用例中使用scheduleAtFixedRate)。
private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
public void startCountdown() {
for (int i = 10; i > 0; i--) {
int countdownNumber = i;
scheduler.schedule(() -> {
System.out.println(countdownNumber);
}, 1, TimeUnit.SECONDS);
}
}
然而,这将只是一次打印所有10个数字,而不是在每个值之间等待一秒钟。我可以绕过这一点的唯一方法(据我所知)是计算绝对延迟,而不是相对延迟。
虽然可以计算每个项目的绝对时间,但这会相当麻烦。Java中是否有某种结构允许我一次对多个项目进行排队,但在每个项目之间的**等待延迟完成,而不是一次处理每个延迟?
2条答案
按热度按时间ffscu2ro1#
TL;医生
scheduleAtFixedRate
将任务调度为越来越多的秒数。执行器服务不需要是单线程的。详情
重新计划自身的任务
Java中是否有某种结构允许我一次对多个项目进行排队,但在每个项目之间等待延迟结束,而不是一次处理每个延迟?
如果在开始调度时有一段未知的时间,那么一次只能运行一个任务,让任务自己重新调度。
要使任务能够重新调度自身,请将对
ScheduledExecutorService
的引用传递给任务对象(您的Runnable
或Callable
)作为构造函数中的参数。任务完成其主要工作后,它会发现/计算下一次运行所需的时间。然后,任务提交自己(this
),以及在下一任务执行之前所经过的时间量。我已经在Stack Overflow上发布了答案,其中包含了重新调度自己的任务的代码。我希望其他人也有。搜索以了解更多。
关于你的问题的"倒计时"方面,请继续阅读。
倒数
您使用计划执行器服务的方法是正确的,问题是您在该类上调用了错误的方法。
调用
schedule
意味着你安排了几个任务在一秒钟后运行,所有这些任务都从你调用schedule
的那一刻开始,所以每个任务都在你调用schedule
的一秒钟后运行,所以这10个任务都在几乎同一时刻等待一秒钟:十个瞬间,每一个瞬间,每一个瞬间就是for
循环继续所需的时间。一米八一米
您要查找的方法是
scheduleAtFixedRate
。引用文档:提交一个周期性操作,该操作在给定的初始延迟之后首先变为启用状态,然后在给定的周期内变为启用状态;即,执行将在初始延迟之后开始,然后是初始延迟+周期,然后是初始延迟+2 * 周期,等等。
请注意,这种方法并不要求
ScheduledExecutorService
是单线程的。完整示例
下面是一个完整的示例应用程序。
运行时:
顺便说一句,由于各种原因,计划任务并不总是准时启动。
另外,要注意跨线程发送到
System.out
的消息并不总是按时间顺序出现在控制台上,如果你关心顺序,总是包括并研究一个时间戳,比如Instant#now
。mec1mxoz2#
您可以在任务中安排下一个呼叫。