【发布时间】:2018-05-10 01:44:42
【问题描述】:
我正在尝试演示一种“随时算法”——一种可以随时停止并返回其当前结果的算法。演示算法只返回 i 的一些数学函数,其中 i 正在增加。它检查是否被中断,如果是,则返回当前值:
static int algorithm(int n) {
int bestSoFar = 0;
for (int i=0; i<n; ++i) {
if (Thread.interrupted())
break;
bestSoFar = (int)Math.pow(i, 0.3);
}
return bestSoFar;
}
在主程序中,我是这样使用的:
Runnable task = () -> {
Instant start = Instant.now();
int bestSoFar = algorithm(1000000000);
double durationInMillis = Duration.between(start, Instant.now()).toMillis();
System.out.println("after "+durationInMillis+" ms, the result is "+bestSoFar);
};
Thread t = new Thread(task);
t.start();
Thread.sleep(1);
t.interrupt();
t = new Thread(task);
t.start();
Thread.sleep(10);
t.interrupt();
t = new Thread(task);
t.start();
Thread.sleep(100);
t.interrupt();
t = new Thread(task);
t.start();
Thread.sleep(1000);
t.interrupt();
}
}
当我运行这个程序时,我得到以下输入:
after 0.0 ms, the result is 7
after 10.0 ms, the result is 36
after 100.0 ms, the result is 85
after 21952.0 ms, the result is 501
也就是说,当我告诉它们时,前三个线程确实被中断了,但最后一个线程在 1 秒后没有被中断 - 它继续工作近 22 秒。为什么会这样?
编辑:我在超时后使用 Future.get 得到了类似的结果。在这段代码中:
Instant start = Instant.now();
ExecutorService executor = Executors.newCachedThreadPool();
Future<?> future = executor.submit(task);
try {
future.get(800, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
future.cancel(true);
double durationInMillis = Duration.between(start, Instant.now()).toMillis();
System.out.println("Timeout after "+durationInMillis+" [ms]");
}
如果超时时间最多为 800,那么一切正常,它会打印出类似“806.0 [ms] 之后的超时时间”的内容。但如果超时为 900,它会打印“Timeout after 5084.0 [ms]”。
编辑 2:我的电脑有 4 个内核。该程序在 Open JDK 8 上运行。
【问题讨论】:
-
循环是真的在循环,还是因为某种原因卡住了?
-
@Carcigenicate 我怎么知道?
-
也适合我。也许程序只有一个 CPU 内核可以使用,并且中断的主线程没有机会运行很长时间?在睡眠之前和中断之前打印时间戳可能会提供一些见解。
-
很有趣,看起来它与安全点和 JIT 编译器有关。我无法用您的示例重现它,但是如果我将 {code}bestSoFar = (int)Math.pow(i, 0.3);{code} 替换为 {code}bestSoFar = i {code} 我经常看到最后一个线程不中断。也许@apangin 可以提供帮助
-
您的系统有多少个内核?您的程序是否与任何其他进程竞争 CPU 资源?
标签: java multithreading jvm