前言:如果这是一个非常愚蠢或者已经有很好的文档记录的错误,我表示歉意。对我来说,现在它看起来非常奇怪,毫无意义。
应用程序
我有一个Java命令行应用程序,在macOS 10.13.4上使用IntelliJ IDEA Ultimate构建,利用下面列出的四个Maven库。它的目的是从网站下载文件,并在此过程中浏览分页结果。
该应用程序的一个特点是能够保持循环运行,如果足够的时间已经过去,它会检查新的结果。为了实现这一点,它在do-while块中作为while
条件调用 Thread.sleep(remainingMillis)
。
问题
应用程序没有任何问题,但是在引入Thread.sleep()
调用之后(我怀疑这是有问题的代码行),发生了一些非常奇怪的行为:应用程序在第一次运行时没有问题,从配置的网站获取了三个项目;然后将其配置为确保在再次运行之前已经过去了60秒。然而,在随后的运行中,日志显示它开始查看第31页(作为示例),在那里找不到结果。在未找到任何内容的情况下,第二次尝试查看第32页,最后一次尝试查看第33页;然后再次等待自扫描迭代开始以来已经过去了60秒。
我不能确认这一点,但似乎它在随后的扫描中继续计数:34、35,然后是36,再次等待。然而,代码应该表明当另一个while
迭代开始时,这应该重新从1开始。
这可能是IntelliJ或Java出了问题,可能只需要清理bin/obj文件夹,但如果这是由于我的代码导致的,我更愿意知道它,这样我将来就不会遇到同样愚蠢的问题。
观察结果
仅仅几天后使用当前配置运行应用程序,意味着它不会调用Thread.sleep()
,因为超过60秒,所以它立即继续下一次迭代;当这种情况发生时,奇怪的页面索引递增问题没有出现 - 相反,下一次迭代从页面1开始,正如它应该做的那样。
之后,运行它,使它在开始下一次迭代之前等待几秒钟的Thread.sleep()
也没有引起问题......非常奇怪。这是一个梦吗?
代码
附注:我添加了Thread.currentThread().interrupt()
来尝试解决这个问题,但似乎没有效果。
public static void main(String[] args) {
do {
startMillis = System.currentTimeMillis();
int itemsFetched = startFetching(agent, config, record, 1, 0);
} while (shouldRepeat(config.getRepeatSeconds(), startMillis));
}
private static boolean shouldRepeat(int repeatSeconds, long startMillis) {
long passedMillis = System.currentTimeMillis() - startMillis;
int repeatMillis = repeatSeconds * 1000;
boolean repeatSecondsReached = passedMillis >= repeatMillis;
if (repeatSeconds < 0) {
return false;
} else if (repeatSecondsReached) {
return true;
}
long remainingMillis = repeatMillis - passedMillis;
int remainingSeconds = (int) (remainingMillis / 1000);
try {
Thread.sleep(remainingMillis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
return true;
}
private static int startFetching(Agenter agent, MyApplicationConfig config, MyApplicationRecord record, int pageIndex, int itemsFetched) {
String categoryCode = config.getCategoryCode();
List<Item> items = agent.getPageOfItems(categoryCode, pageIndex, config);
if (items == null) {
return itemsFetched;
}
int maxItems = config.getMaxItems();
try {
for (Item item : items) {
String itemURL = item.getURL();
agent.downloadItem(itemURL, config, item.getItemCount());
itemsFetched++;
if (maxItems > 0 && itemsFetched >= maxItems) {
return itemsFetched;
}
}
} catch (IOException e) {
// Log
}
return startFetching(agent, config, record, pageIndex + 1, itemsFetched);
}
}
Maven库
commons-cli:commons-cli:1.4
:用于解析命令行参数的工具库。org.apache.logging.log4j:log4j-api:2.11.0
:一个灵活且可扩展的日志框架,提供了强大的日志功能。org.apache.logging.log4j:log4j-core:2.11.0
:log4j-api的核心实现,提供了实际的日志记录和输出功能。org.jsoup:jsoup:1.11.2
:一款Java HTML解析器,可用于从HTML中提取数据。
startFetching
方法接受一个pageIndex
,每次顶层循环运行时都会将其设置为1。因此,我认为那不是问题所在,但我可能错了。 - phantomraapageIndex
为 1 调用startFetching
,这就是当它开始发送页面索引为 31 等的网络请求时让我感到困惑的原因。 - phantomraa