【发布时间】:2018-09-23 16:15:17
【问题描述】:
前言:如果这是一个非常愚蠢的错误或事实上有据可查的东西,我深表歉意。现在对我来说,这似乎很奇怪,完全没有意义。
应用程序
我在 macOS 10.13.4 上的 IntelliJ IDEA Ultimate 中构建了一个 Java 命令行应用程序,它使用了下面列出的四个 Maven 库。其目的是从网站下载文件,并在此过程中浏览分页结果。
此应用程序的一个功能是能够保持循环运行,如果在完成当前扫描时已经经过足够的时间,则检查新结果。为此,它调用Thread.sleep(remainingMillis) 作为do-while 块中while 条件的一部分。
问题
应用程序运行时没有任何问题,但是在引入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.4org.apache.logging.log4j:log4j-api:2.11.0org.apache.logging.log4j:log4j-core:2.11.0org.jsoup:jsoup:1.11.2
【问题讨论】:
-
你能把它减少到minimal test case,这样更容易阅读/诊断吗?
-
我已经大大缩短了代码。希望这更接近您正在寻找的内容。
-
您有大量的日志语句,日志没有说明它使用的是哪个 pageIndex 吗?我的猜测是它与 MyApplicationAgent 类有关,它可能存储在后续运行中不会重置的索引。
-
所以你正在循环使用递归方法?这不奇怪吗?
-
@AlimÖzdemir 确实如此,但那是登录到控制台,所以我现在无法检查,这就是我知道它正在尝试访问第 31、32 和 33 页以及某个点的方式。
startFetching方法接受pageIndex,每次顶部循环运行时将其设置为 1。因此,我不认为会是这样,但我可能错了。
标签: java maven command-line